Browse Source

Faster checking of cardinalities

Yentl Van Tendeloo 9 years ago
parent
commit
44d8048232

+ 34 - 24
bootstrap/conformance_scd.alc

@@ -9,6 +9,10 @@ Boolean function is_direct_instance(model : Element, instance : Element, type :
 	return element_eq(dict_read_node(model["type_mapping"], instance), type)
 
 Boolean function is_nominal_instance(model : Element, instance : Element, type : Element):
+	if (bool_not(set_in_node(model["metamodel"]["model"], type))):
+		// type is not even in the specified metamodel, so this will never work
+		return False
+
 	return is_nominal_subtype(model["metamodel"], dict_read_node(model["type_mapping"], instance), type)
 
 Boolean function is_nominal_subtype(metamodel : Element, subclass : Element, superclass : Element):
@@ -84,8 +88,10 @@ String function conformance_scd(model : Element):
 	Element check_list
 	Element check_type
 	Element cardinalities
+	Element scd
 
 	// Load in variables
+	scd = import_node("models/SimpleClassDiagrams")
 	metamodel = model["metamodel"]
 	typing = model["type_mapping"]
 	cardinalities = create_node()
@@ -100,22 +106,25 @@ String function conformance_scd(model : Element):
 	Element tmp_dict
 	while (0 < list_len(keys)):
 		key = set_pop(keys)
-		tmp_dict = create_node()
-		slc = read_attribute(metamodel, key, "source_lower_cardinality")
-		suc = read_attribute(metamodel, key, "source_upper_cardinality")
-		tlc = read_attribute(metamodel, key, "target_lower_cardinality")
-		tuc = read_attribute(metamodel, key, "target_upper_cardinality")
-		if (element_neq(slc, read_root())):
-			dict_add(tmp_dict, "slc", slc)
-		if (element_neq(suc, read_root())):
-			dict_add(tmp_dict, "suc", suc)
-		if (element_neq(tlc, read_root())):
-			dict_add(tmp_dict, "tlc", tlc)
-		if (element_neq(tuc, read_root())):
-			dict_add(tmp_dict, "tuc", tuc)
-
-		if (list_len(tmp_dict) > 0):
-			dict_add(cardinalities, key, tmp_dict)
+		if (is_nominal_instance(metamodel, metamodel["model"][key], scd["model"]["Association"])):
+			tmp_dict = create_node()
+			slc = read_attribute(metamodel, key, "source_lower_cardinality")
+			suc = read_attribute(metamodel, key, "source_upper_cardinality")
+			tlc = read_attribute(metamodel, key, "target_lower_cardinality")
+			tuc = read_attribute(metamodel, key, "target_upper_cardinality")
+			if (element_neq(slc, read_root())):
+				dict_add(tmp_dict, "slc", slc)
+			if (element_neq(suc, read_root())):
+				dict_add(tmp_dict, "suc", suc)
+			if (element_neq(tlc, read_root())):
+				dict_add(tmp_dict, "tlc", tlc)
+			if (element_neq(tuc, read_root())):
+				dict_add(tmp_dict, "tuc", tuc)
+
+			if (list_len(tmp_dict) > 0):
+				dict_add(cardinalities, key, tmp_dict)
+		else:
+			log("Not checking cardinalities of " + key)
 
 	// Iterate over each element of the model, finding out whether everything is fine
 	keys = dict_keys(model["model"])
@@ -154,7 +163,8 @@ String function conformance_scd(model : Element):
 		Integer lower_val
 		Integer upper_val
 		Integer instances
-		check_list = allPossibleIncoming(model, model_name)
+
+		check_list = selectPossibleIncoming(model, model_name, dict_keys(cardinalities))
 		while (0 < list_len(check_list)):
 			check_type = set_pop(check_list)
 			if (dict_in(cardinalities, reverseKeyLookup(metamodel["model"], check_type))):
@@ -173,7 +183,7 @@ String function conformance_scd(model : Element):
 						return "Upper cardinality violation for incoming edge at " + model_name
 
 		// Identical, but for outgoing, and thus for A in the figure
-		check_list = allPossibleOutgoing(model, model_name)
+		check_list = selectPossibleOutgoing(model, model_name, dict_keys(cardinalities))
 		while (0 < list_len(check_list)):
 			check_type = set_pop(check_list)
 			if (dict_in(cardinalities, reverseKeyLookup(metamodel["model"], check_type))):
@@ -201,18 +211,18 @@ String function conformance_scd(model : Element):
 		metamodel_element = set_pop(metamodel_keys)
 
 		// Lower multiplicities
-		attr_value = read_attribute(metamodel, metamodel_element, "lower_multiplicity")
+		attr_value = read_attribute(metamodel, metamodel_element, "lower_cardinality")
 		if (element_neq(attr_value, read_root())):
-			// We have defined a lower multiplicity, so check number of instances!
+			// We have defined a lower cardinality, so check number of instances!
 			if (attr_value > list_len(allInstances(model, metamodel["model"][metamodel_element]))):
-				return "Lower multiplicity violated for class: " + metamodel_element
+				return "Lower cardinality violated for class: " + metamodel_element
 
 		// Upper multiplicities
-		attr_value = read_attribute(metamodel, metamodel_element, "upper_multiplicity")
+		attr_value = read_attribute(metamodel, metamodel_element, "upper_cardinality")
 		if (element_neq(attr_value, read_root())):
-			// We have defined a lower multiplicity, so check number of instances!
+			// We have defined a lower cardinality, so check number of instances!
 			if (attr_value < list_len(allInstances(model, metamodel["model"][metamodel_element]))):
-				return "Upper multiplicity violated for class: " + metamodel_element
+				return "Upper cardinality violated for class: " + metamodel_element
 
 	// Structure seems fine, now do static semantics
 	if (dict_in(metamodel, "constraints")):

+ 19 - 61
bootstrap/metamodels.alc

@@ -26,32 +26,6 @@ Element function create_metamodels():
 		model_add_edge(scd, "attr_name", "association_attr", "name")
 		model_add_node(scd, "Integer")
 
-		// TODO: possible to use instantiate_named here?
-		// Lower multiplicity on classes
-		model_add_value(scd, "lower_multiplicity", "lower_multiplicity")
-		model_add_edge(scd, "class_to_lm", "Class", "Integer")
-		model_add_edge(scd, "lm_name", "class_to_lm", "lower_multiplicity")
-		// Upper multiplicity on classes
-		model_add_value(scd, "upper_multiplicity", "upper_multiplicity")
-		model_add_edge(scd, "class_to_um", "Class", "Integer")
-		model_add_edge(scd, "um_name", "class_to_um", "upper_multiplicity")
-		// Source lower multiplicity on associations
-		model_add_value(scd, "source_lower_cardinality", "source_lower_cardinality")
-		model_add_edge(scd, "assoc_to_slc", "Association", "Integer")
-		model_add_edge(scd, "slc_name", "assoc_to_slc", "source_lower_cardinality")
-		// Source upper multiplicity on associations
-		model_add_value(scd, "source_upper_cardinality", "source_upper_cardinality")
-		model_add_edge(scd, "assoc_to_suc", "Association", "Integer")
-		model_add_edge(scd, "suc_name", "assoc_to_suc", "source_upper_cardinality")
-		// Target lower multiplicity on associations
-		model_add_value(scd, "target_lower_cardinality", "target_lower_cardinality")
-		model_add_edge(scd, "assoc_to_tlc", "Association", "Integer")
-		model_add_edge(scd, "tlc_name", "assoc_to_tlc", "target_lower_cardinality")
-		// Target upper multiplicity on associations
-		model_add_value(scd, "target_upper_cardinality", "target_upper_cardinality")
-		model_add_edge(scd, "assoc_to_tuc", "Association", "Integer")
-		model_add_edge(scd, "tuc_name", "assoc_to_tuc", "target_upper_cardinality")
-
 		retype_model(scd, scd)
 		define_inheritance(scd, "Inheritance")
 		retype(scd, "Class", "Class")
@@ -71,39 +45,20 @@ Element function create_metamodels():
 		retype(scd, "association_attr", "Association")
 		retype(scd, "attr_name", "association_attr")
 		retype(scd, "Integer", "Type")
-		// TODO: with instantiate_named, after all previous retypings?
-		// Lower multiplicity on classes
-		retype(scd, "lower_multiplicity", "String")
-		retype(scd, "lm_name", "association_attr")
-		retype(scd, "class_to_um", "Association")
-		// Upper multiplicity on classes
-		retype(scd, "upper_multiplicity", "String")
-		retype(scd, "class_to_lm", "Association")
-		retype(scd, "um_name", "association_attr")
-		// Source lower cardinality on associations
-		retype(scd, "source_lower_cardinality", "String")
-		retype(scd, "assoc_to_slc", "Association")
-		retype(scd, "slc_name", "association_attr")
-		// Source upper cardinality on associations
-		retype(scd, "source_upper_cardinality", "String")
-		retype(scd, "assoc_to_suc", "Association")
-		retype(scd, "suc_name", "association_attr")
-		// Target lower cardinality on associations
-		retype(scd, "target_lower_cardinality", "String")
-		retype(scd, "assoc_to_tlc", "Association")
-		retype(scd, "tlc_name", "association_attr")
-		// Target upper cardinality on associations
-		retype(scd, "target_upper_cardinality", "String")
-		retype(scd, "assoc_to_tuc", "Association")
-		retype(scd, "tuc_name", "association_attr")
 
-		// TODO: try this
-		//instantiate_named(scd, "Association", "lower_multiplicity", "Class", "Integer")
-		//instantiate_named(scd, "Association", "upper_multiplicity", "Class", "Integer")
-		//instantiate_named(scd, "Association", "source_lower_multiplicity", "Association", "Integer")
-		//instantiate_named(scd, "Association", "source_upper_multiplicity", "Association", "Integer")
-		//instantiate_named(scd, "Association", "target_lower_multiplicity", "Association", "Integer")
-		//instantiate_named(scd, "Association", "target_upper_multiplicity", "Association", "Integer")
+		// Add some attributes "the nice way" now that everything is typed
+		instantiate_link(scd, "Association", "lc", "Class", "Integer")
+		instantiate_attribute(scd, "lc", "name", "lower_cardinality")
+		instantiate_link(scd, "Association", "uc", "Class", "Integer")
+		instantiate_attribute(scd, "uc", "name", "upper_cardinality")
+		instantiate_link(scd, "Association", "slc", "Association", "Integer")
+		instantiate_attribute(scd, "slc", "name", "source_lower_cardinality")
+		instantiate_link(scd, "Association", "suc", "Association", "Integer")
+		instantiate_attribute(scd, "suc", "name", "source_upper_cardinality")
+		instantiate_link(scd, "Association", "tlc", "Association", "Integer")
+		instantiate_attribute(scd, "tlc", "name", "target_lower_cardinality")
+		instantiate_link(scd, "Association", "tuc", "Association", "Integer")
+		instantiate_attribute(scd, "tuc", "name", "target_upper_cardinality")
 
 		export_node("models/SimpleClassDiagrams", scd)
 
@@ -115,9 +70,12 @@ Element function create_metamodels():
 		instantiate_node(pn, "Type", "Integer")
 		instantiate_link(pn, "Association", "P2T", "Place", "Transition")
 		instantiate_link(pn, "Association", "T2P", "Transition", "Place")
-		instantiate_named(pn, "Association", "tokens", "Place", "Integer")
-		instantiate_named(pn, "Association", "weight", "P2T", "Integer")
-		instantiate_named(pn, "Association", "weight", "T2P", "Integer")
+		instantiate_link(pn, "Association", "Place_tokens", "Place", "Integer")
+		instantiate_attribute(pn, "Place_tokens", "name", "tokens")
+		instantiate_link(pn, "Association", "P2T_weight", "P2T", "Integer")
+		instantiate_attribute(pn, "P2T_weight", "name", "weight")
+		instantiate_link(pn, "Association", "T2P_weight", "T2P", "Integer")
+		instantiate_attribute(pn, "T2P_weight", "name", "weight")
 
 		set_model_constraints(pn, petrinet_constraints)
 		export_node("models/PetriNets", pn)

+ 0 - 16
bootstrap/modelling.alc

@@ -99,7 +99,6 @@ Element function find_attribute_type(model : Element, elem : String, name : Stri
 
 	if (element_eq(mm_elem, read_root())):
 		// Couldn't find element, so is not allowed!
-		log("Undefined attribute!")
 		return read_root()
 	else:
 		return getName(model["metamodel"], dict_read_edge(mm_elem, name))
@@ -167,18 +166,6 @@ String function instantiate_link(model : Element, type : String, name : String,
 
 	return actual_name
 
-Void function instantiate_named(model : Element, type : String, name : String, source : String, destination : String):
-	// Special helper function to create an edge and name it
-	String link_name
-	String name_name
-
-	link_name = instantiate_link(model, type, "", source, destination)
-	//name_name = model_add_value(model, "", name)
-	//retype(model, name_name, "String")
-	instantiate_attribute(model, link_name, "name", name)
-
-	return
-
 Void function define_inheritance(model : Element, inheritance_name : String):
 	// Set the inheritance link to the one defined in our own metamodel, given by the specified name
 	dict_add(model, "inheritance", model["metamodel"]["model"][inheritance_name])
@@ -208,7 +195,6 @@ Element function read_attribute(model : Element, element : String, attribute : S
 		attr_link = set_pop(attr_links)
 		return read_edge_dst(attr_link)
 
-	log("Could not find attribute!")
 	return read_root()
 
 Void function unset_attribute(model : Element, element : String, attribute : String):
@@ -250,8 +236,6 @@ Void function construct_model():
 			output(instantiate_model(input()))
 		elif (command == "instantiate_node"):
 			instantiate_node(input(), input(), input())
-		elif (command == "instantiate_named"):
-			instantiate_named(input(), input(), input(), input(), input())
 		elif (command == "instantiate_attribute"):
 			instantiate_attribute(input(), input(), input(), input())
 		elif (command == "instantiate_link"):

+ 8 - 11
bootstrap/object_operations.alc

@@ -25,10 +25,10 @@ Element function allInstances(model : Element, type : Element):
 	
 	return result
 
-Element function allPossibleIncoming(model : Element, target : String):
+Element function selectPossibleIncoming(model : Element, target : String, limit_set : Element):
 	// Find all possible incoming link types for the target model
 	// Should also include those specified on the superclass(es)
-	Element all_elems
+
 	String type
 	Element metamodel
 	Element elem
@@ -36,10 +36,9 @@ Element function allPossibleIncoming(model : Element, target : String):
 
 	result = create_node()
 	metamodel = model["metamodel"]
-	all_elems = dict_keys(metamodel["model"])
-	
-	while (0 < list_len(all_elems)):
-		type = set_pop(all_elems)
+
+	while (0 < list_len(limit_set)):
+		type = set_pop(limit_set)
 		elem = metamodel["model"][type]
 		if (is_edge(elem)):
 			if (is_nominal_instance(model, model["model"][target], read_edge_src(elem))):
@@ -47,10 +46,9 @@ Element function allPossibleIncoming(model : Element, target : String):
 	
 	return result
 
-Element function allPossibleOutgoing(model : Element, source : String):
+Element function selectPossibleOutgoing(model : Element, source : String, limit_set : Element):
 	// Find all possible outgoing link types for the source model
 	// Should also include those specified on the superclass(es)
-	Element all_elems
 	String type
 	Element metamodel
 	Element elem
@@ -58,10 +56,9 @@ Element function allPossibleOutgoing(model : Element, source : String):
 
 	result = create_node()
 	metamodel = model["metamodel"]
-	all_elems = dict_keys(model["metamodel"]["model"])
 	
-	while (0 < list_len(all_elems)):
-		type = set_pop(all_elems)
+	while (0 < list_len(limit_set)):
+		type = set_pop(limit_set)
 		elem = metamodel["model"][type]
 		if (is_edge(elem)):
 			if (is_nominal_instance(model, model["model"][source], read_edge_dst(elem))):

+ 34 - 12
integration/test_constructors_models.py

@@ -58,6 +58,23 @@ retype = [
         '"exit"',
     ]
 
+bottom_attributes = [
+        '"model"',
+        '"instantiate_link"', 1, '"Association"', '"lc"', '"Class"', '"Integer"',
+        '"instantiate_attribute"', 1, '"lc"', '"name"', '"lower_cardinality"',
+        '"instantiate_link"', 1, '"Association"', '"uc"', '"Class"', '"Integer"',
+        '"instantiate_attribute"', 1, '"lc"', '"name"', '"upper_cardinality"',
+        '"instantiate_link"', 1, '"Association"', '"slc"', '"Association"', '"Integer"',
+        '"instantiate_attribute"', 1, '"slc"', '"name"', '"source_lower_cardinality"',
+        '"instantiate_link"', 1, '"Association"', '"suc"', '"Association"', '"Integer"',
+        '"instantiate_attribute"', 1, '"suc"', '"name"', '"source_upper_cardinality"',
+        '"instantiate_link"', 1, '"Association"', '"tlc"', '"Association"', '"Integer"',
+        '"instantiate_attribute"', 1, '"tlc"', '"name"', '"target_lower_cardinality"',
+        '"instantiate_link"', 1, '"Association"', '"tuc"', '"Association"', '"Integer"',
+        '"instantiate_attribute"', 1, '"tuc"', '"name"', '"target_upper_cardinality"',
+        '"exit"',
+    ]
+
 instantiate_scd = [
         '"model"',
         '"instantiate_model"', 1, 2,
@@ -67,9 +84,12 @@ instantiate_scd = [
         '"instantiate_node"', 2, '"Type"', '"Integer"',
         '"instantiate_link"', 2, '"Association"', '"P2T"', '"Place"', '"Transition"',
         '"instantiate_link"', 2, '"Association"', '"T2P"', '"Transition"', '"Place"',
-        '"instantiate_named"', 2, '"Association"', '"tokens"', '"Place"', '"Integer"',
-        '"instantiate_named"', 2, '"Association"', '"weight"', '"P2T"', '"Integer"',
-        '"instantiate_named"', 2, '"Association"', '"weight"', '"T2P"', '"Integer"',
+        '"instantiate_link"', 2, '"Association"', '"Place_tokens"', '"Place"', '"Integer"',
+        '"instantiate_attribute"', 2, '"Place_tokens"', '"name"', '"tokens"',
+        '"instantiate_link"', 2, '"Association"', '"weight"', '"P2T"', '"Integer"',
+        '"instantiate_attribute"', 2, '"P2T_weight"', '"name"', '"weight"',
+        '"instantiate_link"', 2, '"Association"', '"weight"', '"T2P"', '"Integer"',
+        '"instantiate_attribute"', 2, '"T2P_weight"', '"name"', '"weight"',
         '"exit"',
     ]
 
@@ -101,8 +121,10 @@ instantiate_example = [
         '"instantiate_node"', 2, '"Class"', '"B"',
         '"instantiate_node"', 2, '"Class"', '"C"',
         '"instantiate_link"', 2, '"Inheritance"', '"b_inherits_a"', '"B"', '"A"',
-        '"instantiate_named"', 2, '"Association"', '"tokens"', '"A"', '"B"',
-        '"instantiate_named"', 2, '"Association"', '"tokens"', '"C"', '"B"',
+        '"instantiate_link"', 2, '"Association"', '"A_tokens"', '"A"', '"B"',
+        '"instantiate_attribute"', 2, '"A_tokens"', '"name"', '"tokens"',
+        '"instantiate_link"', 2, '"Association"', '"C_tokens"', '"C"', '"B"',
+        '"instantiate_attribute"', 2, '"C_tokens"', '"name"', '"tokens"',
         '"exit"',
         '"model"',
         '"instantiate_model"', 2, 3,
@@ -193,37 +215,37 @@ def conformance_check(node):
 
 class TestConstructorsModels(unittest.TestCase):
     def test_constructors_instantiate_bottom(self):
-        commands = bottom + retype + conformance_check(1) + ['"return"', 'false']
+        commands = bottom + retype + bottom_attributes + conformance_check(1) + ['"return"', 'false']
         self.assertTrue(run_barebone(commands, ["OK"], 1))
 
     def test_constructors_instantiate_scd(self):
-        commands = bottom + retype + instantiate_scd + conformance_check(2) + ['"return"', 'false']
+        commands = bottom + retype + bottom_attributes + instantiate_scd + conformance_check(2) + ['"return"', 'false']
         self.assertTrue(run_barebone(commands, ["OK"], 1))
 
     def test_constructors_instantiate_pn(self):
-        commands = bottom + retype + instantiate_scd + instantiate_pn + conformance_check(3) + ['"return"', 'false']
+        commands = bottom + retype + bottom_attributes + instantiate_scd + instantiate_pn + conformance_check(3) + ['"return"', 'false']
         self.assertTrue(run_barebone(commands, ["OK"], 1))
 
     def test_constructors_instantiate_example(self):
-        commands = bottom + retype + instantiate_example + conformance_check(2) + conformance_check(3) + ['"return"', 'false']
+        commands = bottom + retype + bottom_attributes + instantiate_example + conformance_check(2) + conformance_check(3) + ['"return"', 'false']
         self.assertTrue(run_barebone(commands, ["OK", "OK"], 1))
 
     def test_constructors_is_direct_instance(self):
-        commands = bottom + retype + instantiate_example + is_direct_instance + ['"return"', 'false']
+        commands = bottom + retype + bottom_attributes + instantiate_example + is_direct_instance + ['"return"', 'false']
         expected = ['True', 'False', 'False',
                     'False', 'True', 'False',
                     'False', 'False', 'True']
         self.assertTrue(run_barebone(commands, expected, 1))
 
     def test_constructors_is_nominal_instance(self):
-        commands = bottom + retype + instantiate_example + is_nominal_instance + ['"return"', 'false']
+        commands = bottom + retype + bottom_attributes + instantiate_example + is_nominal_instance + ['"return"', 'false']
         expected = ['True', 'True', 'False',
                     'False', 'True', 'False',
                     'False', 'False', 'True']
         self.assertTrue(run_barebone(commands, expected, 1))
 
     def test_constructors_is_structural_instance(self):
-        commands = bottom + retype + instantiate_example + is_structural_instance + ['"return"', 'false']
+        commands = bottom + retype + bottom_attributes + instantiate_example + is_structural_instance + ['"return"', 'false']
         expected = ['True', 'False', 'True',
                     'True', 'True', 'True',
                     'True', 'False', 'True']

+ 0 - 1
interface/HUTN/includes/modelling.alh

@@ -12,7 +12,6 @@ Element function get_superclasses(model : Element, elem : Element)
 Element function find_attribute_definer(model : Element, elem : Element, name : String)
 Void function instantiate_attribute(model : Element, element : String, attribute_name : String, value : Element)
 String function instantiate_link(model : Element, type : String, name : String, source : String, destination : String)
-Void function instantiate_named(model : Element, type : String, name : String, source : String, destination : String)
 Void function define_inheritance(model : Element, inheritance_name : String)
 Void function unset_attribute(model : Element, elem : String, name : String)
 Void function construct_model()

+ 2 - 2
interface/HUTN/includes/object_operations.alh

@@ -7,5 +7,5 @@ Element function getInstantiatableAttributes(a: Element, b: Element)
 String function getName(a: Element, b: Element)
 String function reverseKeyLookup(a: Element, b: Element)
 String function print_dict(dict : Element)
-Element function allPossibleIncoming(model : Element, target : String)
-Element function allPossibleOutgoing(model : Element, source : String)
+Element function selectPossibleIncoming(model : Element, target : String, limit_set : Element)
+Element function selectPossibleOutgoing(model : Element, source : String, limit_set : Element)