Browse Source

New type mapping storage method (faster and more correct)

Yentl Van Tendeloo 7 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):
 		while (set_len(elems) > 0):
 			elem = set_pop(elems)
 			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
 				// An edge, and there is always exactly one, so type
 				retype(model, elem, edge_element)
 				retype(model, elem, edge_element)
 
 
 				// The source and target are ALWAYS typed as well!
 				// The source and target are ALWAYS typed as well!
 				retype(model, readAssociationSource(model, elem), node_source_element)
 				retype(model, readAssociationSource(model, elem), node_source_element)
 				retype(model, readAssociationDestination(model, elem), node_target_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
 	// 3) (optional) verify that the mapping is correct with conformance checking
 	// TODO
 	// TODO

+ 3 - 1
bootstrap/type_mapping.mvc

@@ -3,7 +3,9 @@ import models/SimpleClassDiagrams as SCD
 SCD type_mapping {
 SCD type_mapping {
     Class Instance {}
     Class Instance {}
     Class Type {}
     Class Type {}
-    Association TypeLink (Instance, Type) {}
+    Class Root {}
+    Association TypeLink (Root, Type) {}
+    Association InstanceLink (TypeLink, Instance) {}
 }
 }
 
 
 export type_mapping to models/TypeMapping
 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):
 Element function get_type_mapping(model : Element):
 	// Deserialize dictionary as model
 	// 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):
 Void function set_type_mapping(model : Element, type_mapping_model : Element):
 	// Serialize model to dictionary
 	// 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!
 	return!
 
 
 Element function elements_typed_by(model : Element, type_name : String):
 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!
 	return result!
 
 
 Element function get_type_mapping_as_dict(model : Element):
 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 function read_type(model : Element, name : String):
 	String result
 	String result
 	Element tm
 	Element tm
 	if (dict_in(model["model"], name)):
 	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)):
 			if (dict_in(model["metamodel"]["model"], result)):
 				return result!
 				return result!
 			else:
 			else:
@@ -140,21 +45,34 @@ String function read_type(model : Element, name : String):
 
 
 Void function retype(model : Element, element : String, type : String):
 Void function retype(model : Element, element : String, type : String):
 	// Retype a model, deleting any previous type the element had
 	// 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!
 	return!
 
 
 Void function new_type_mapping(model : Element):
 Void function new_type_mapping(model : Element):
 	dict_overwrite(model, "type_mapping", dict_create())
 	dict_overwrite(model, "type_mapping", dict_create())
+	dict_add(model["type_mapping"], "root", create_node())
 	return !
 	return !
 
 
 Void function remove_type(model : Element, name : String):
 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 !
 	return !

+ 12 - 7
kernel/modelverse_kernel/compiled.py

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

+ 1 - 0
unit/test_all.py

@@ -415,6 +415,7 @@ class TestModelverse(unittest.TestCase):
         count_nodes = 0
         count_nodes = 0
         count_edges = 0
         count_edges = 0
         for entry in element_list_nice("test/PetriNet"):
         for entry in element_list_nice("test/PetriNet"):
+            print(entry)
             assert entry["__type"] in ["Node", "Edge"]
             assert entry["__type"] in ["Node", "Edge"]
             if entry["__type"] == "Node":
             if entry["__type"] == "Node":
                 assert len(entry) == 2
                 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)
 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 author: Yentl Van Tendeloo
 Model name:   MvK Server
 Model name:   MvK Server