Browse Source

Significant bugfixes for conformance relation: added type mapping MM, add conformance_finding algorithm that deduces a type mapping automatically for type mapping models

Yentl Van Tendeloo 7 years ago
parent
commit
3cdc651ed9

+ 40 - 22
bootstrap/conformance_finding.alc

@@ -44,46 +44,64 @@ Boolean function find_type_mapping(model : Element):
 		Element elems
 		Element elems
 		String elem
 		String elem
 
 
-		String node_element
+		String node_source_element
+		String node_target_element
 		String edge_element
 		String edge_element
-		node_element = read_root()
-		edge_element = read_root()
 
 
 		Element nodes
 		Element nodes
 		Element edges
 		Element edges
 		nodes = allInstances(model["metamodel"], "Class")
 		nodes = allInstances(model["metamodel"], "Class")
 		edges = allInstances(model["metamodel"], "Association")
 		edges = allInstances(model["metamodel"], "Association")
 
 
-		if (set_len(nodes) > 1):
-			log("Got nodes: " + set_to_string(nodes))
-			log("Multiple nodes detected!")
-			return False!
-		elif (set_len(edges) > 1):
-			log("Got edges: " + set_to_string(edges))
-			log("Multiple edges detected!")
-			return False!
-		elif (set_len(nodes) != 1):
-			log("No node found!")
-			return False!
-		elif (set_len(edges) != 1):
-			log("No edge found!")
-			return False!
-		else:
-			node_element = set_pop(nodes)
+		log("Searching for type...")
+		if (bool_and(set_len(edges) == 1, set_len(nodes) == 1)):
+			// Simple allocation: this seems like conformance bottom
+			node_source_element = set_pop(nodes)
+			node_target_element = node_source_element
+			edge_element = set_pop(edges)
+			log("Found node: " + node_source_element)
+			log("Found edge: " + edge_element)
+
+		elif (bool_and(set_len(edges) == 1, set_len(nodes) == 2)):
+			// Simple allocation: this seems like a type mapping
+			// Make sure to check that the edge goes from one node to the other!
 			edge_element = set_pop(edges)
 			edge_element = set_pop(edges)
-			log("Found node: " + node_element)
+			node_source_element = readAssociationSource(model["metamodel"], edge_element)
+			node_target_element = readAssociationDestination(model["metamodel"], edge_element)
+
+			if (value_eq(node_source_element, node_target_element)):
+				log("Source and target are the same, meaning that the second node is unknown")
+				return False!
+
 			log("Found edge: " + edge_element)
 			log("Found edge: " + edge_element)
+			log("Found source node: " + node_source_element)
+			log("Found target node: " + node_target_element)
+
+		else:
+			log("Could not automatically deduce mapping in a trivial way!")
+			return False!
+
 
 
-		// Now we have bot an edge_element and node_element of the metamodel
+		// Now we have both an edge_element and node_element of the metamodel
 		// Now just trivially bind all elements!
 		// Now just trivially bind all elements!
+		log("Searching for type...")
 		elems = dict_keys(model["model"])
 		elems = dict_keys(model["model"])
 		while (set_len(elems) > 0):
 		while (set_len(elems) > 0):
 			elem = set_pop(elems)
 			elem = set_pop(elems)
 
 
 			if (is_edge(model["model"][elem])):
 			if (is_edge(model["model"][elem])):
+				// An edge, and there is always exactly one, so type
 				retype(model, elem, edge_element)
 				retype(model, elem, edge_element)
+			elif (node_source_element == node_target_element):
+				// A node, and we are sure that there is only one
+				retype(model, elem, node_source_element)
 			else:
 			else:
-				retype(model, elem, node_element)
+				// We have an element and know that there is an edge connecting them
+				// If there is an outgoing link, we make it "node_target_element", otherwise "node_source_element"
+				if (read_nr_out(model["model"][elem]) > 0):
+					retype(model, elem, node_source_element)
+				else:
+					retype(model, elem, node_target_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

+ 5 - 4
bootstrap/core_algorithm.alc

@@ -111,6 +111,7 @@ Element function get_full_model(model_id : String, metamodel_id : String):
 		Element mm
 		Element mm
 		mm = get_full_model(metamodel_id, get_entry_id("formalisms/SimpleClassDiagrams"))
 		mm = get_full_model(metamodel_id, get_entry_id("formalisms/SimpleClassDiagrams"))
 		if (element_eq(mm, read_root())):
 		if (element_eq(mm, read_root())):
+			log("Error finding type mapping...")
 			return read_root()!
 			return read_root()!
 		else:
 		else:
 			dict_add(m, "metamodel", mm)
 			dict_add(m, "metamodel", mm)
@@ -2340,14 +2341,14 @@ String function cmd_model_types(model_name : String):
 		model_id = get_entry_id(model_name)
 		model_id = get_entry_id(model_name)
 
 
 		Element types
 		Element types
-		String type
+		String type_link
 		String result
 		String result
 
 
 		result = "Success: "
 		result = "Success: "
-		types = allAssociationDestinations(core, model_id, "instanceOf")
+		types = allOutgoingAssociationInstances(core, model_id, "instanceOf")
 		while (set_len(types) > 0):
 		while (set_len(types) > 0):
-			type = set_pop(types)
-			result = string_join(result, full_name(type) + "\n")
+			type_link = set_pop(types)
+			result = result + full_name(readAssociationDestination(core, type_link)) + ", " + full_name(set_pop(allAssociationDestinations(core, type_link, "typing"))) + ", " + full_name(set_pop(allAssociationDestinations(core, type_link, "semantics")))+ "\n"
 
 
 		return result!
 		return result!
 	else:
 	else:

+ 9 - 0
bootstrap/type_mapping.mvc

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

+ 1 - 1
wrappers/classes/modelverse.xml

@@ -938,7 +938,7 @@
 
 
                         <transition cond="self.expect_response_partial('Success: ')" target="../../wait_for_action/history">
                         <transition cond="self.expect_response_partial('Success: ')" target="../../wait_for_action/history">
                             <raise event="result">
                             <raise event="result">
-                                <parameter expr="set(self.split_response(self.responses.pop(0)))"/>
+                                <parameter expr="set([tuple(i.split(', ')) for i in self.split_response(self.responses.pop(0))])"/>
                             </raise>
                             </raise>
                         </transition>
                         </transition>
                     </state>
                     </state>

+ 2 - 2
wrappers/modelverse.py

@@ -239,8 +239,8 @@ def model_list_full(location):
     INPUT("model_list_full", [location])
     INPUT("model_list_full", [location])
     return OUTPUT()
     return OUTPUT()
 
 
-def verify(model_name, metamodel_name):
-    INPUT("verify", [model_name, metamodel_name])
+def verify(model_name, metamodel_name, conformance_function=""):
+    INPUT("verify", [model_name, metamodel_name, conformance_function])
     return OUTPUT()
     return OUTPUT()
 
 
 def model_overwrite(model_name, new_model):
 def model_overwrite(model_name, new_model):

+ 2 - 2
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:   Thu May 24 11:42:22 2018
+Date:   Thu May 24 16:50:33 2018
 
 
 Model author: Yentl Van Tendeloo
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server
 Model name:   MvK Server
@@ -2836,7 +2836,7 @@ class Modelverse(RuntimeClassBase):
         return self.expect_response('Success')
         return self.expect_response('Success')
     
     
     def _initialized_behaviour_operations_model_types_0_exec(self, parameters):
     def _initialized_behaviour_operations_model_types_0_exec(self, parameters):
-        self.raiseInternalEvent(Event("result", None, [set(self.split_response(self.responses.pop(0)))]))
+        self.raiseInternalEvent(Event("result", None, [set([tuple(i.split(', ')) for i in self.split_response(self.responses.pop(0))])]))
     
     
     def _initialized_behaviour_operations_model_types_0_guard(self, parameters):
     def _initialized_behaviour_operations_model_types_0_guard(self, parameters):
         return self.expect_response_partial('Success: ')
         return self.expect_response_partial('Success: ')