Browse Source

RAMification now generates a single model, including the schedule and
all

Yentl Van Tendeloo 8 years ago
parent
commit
25a3fc7f94

BIN
bootstrap/bootstrap.m.gz


+ 12 - 0
bootstrap/object_operations.alc

@@ -190,3 +190,15 @@ String function followAssociation(model : Element, element_name : String, associ
 		set_add(result, readAssociationDestination(model, set_pop(assocs)))
 
 	return result!
+
+Element function allAssociationDestinations(model : Element, name : String, association_type : String):
+	Element tmp
+	Element result
+
+	result = create_node()
+	tmp = allOutgoingAssociationInstances(model, name, association_type)
+
+	while (read_nr_out(tmp) > 0):
+		set_add(result, readAssociationDestination(model, set_pop(tmp)))
+
+	return result!

+ 174 - 116
bootstrap/ramify.alc

@@ -3,7 +3,7 @@ include "object_operations.alh"
 include "modelling.alh"
 include "metamodels.alh"
 
-Element function ramify_func(model : Element, prepost : String):
+Element function ramify(model : Element):
 	// Create new model structure
 	Element new_model
 	new_model = create_node()
@@ -16,14 +16,10 @@ Element function ramify_func(model : Element, prepost : String):
 	Element old_m
 	Element new_m
 	Element mm
-	String inheritor
 	new_m = new_model["model"]
 	old_m = model["model"]
 	mm = new_model["metamodel"]["model"]
 
-	Boolean is_pre
-	is_pre = (prepost == "pre")
-
 	// Add in some primitives
 	instantiate_node(new_model, "Class", "Natural")
 	instantiate_node(new_model, "Class", "String")
@@ -33,107 +29,89 @@ Element function ramify_func(model : Element, prepost : String):
 	add_AL_to_MM(new_model)
 
 	// Add some default elements
-	if (is_pre):
-		//	Class LHS {
-		//		constraint : funcdef {
-		//			target_upper_cardinality = 1
-		//		}
-		//		upper_cardinality = 1
-		//		lower_cardinality = 1
-		//	}
-		instantiate_node(new_model, "Class", "LHS")
-		instantiate_attribute(new_model, "LHS", "lower_cardinality", 1)
-		instantiate_attribute(new_model, "LHS", "upper_cardinality", 1)
-		instantiate_link(new_model, "Association", "LHS_constraint", "LHS", "funcdef")
-		instantiate_attribute(new_model, "LHS_constraint", "name", "constraint")
-		instantiate_attribute(new_model, "LHS_constraint", "target_upper_cardinality", 1)
-
-		//	Class NAC {}
-		//instantiate_node(new_model, "Class", "NAC")
-
-		//	Class Pre_Element {
-		//		label : String {
-		//			target_lower_cardinality = 1
-		//			target_upper_cardinality = 1
-		//		}
-		//		constraint : funcdef {
-		//			target_upper_cardinality = 1
-		//		}
-		//	}
-		instantiate_node(new_model, "Class", "Pre_Element")
-		instantiate_link(new_model, "Association", "Pre_Element_label", "Pre_Element", "String")
-		instantiate_attribute(new_model, "Pre_Element_label", "name", "label")
-		instantiate_attribute(new_model, "Pre_Element_label", "target_lower_cardinality", 1)
-		instantiate_attribute(new_model, "Pre_Element_label", "target_upper_cardinality", 1)
-		instantiate_link(new_model, "Association", "Pre_Element_constraint", "Pre_Element", "funcdef")
-		instantiate_attribute(new_model, "Pre_Element_constraint", "name", "constraint")
-		instantiate_attribute(new_model, "Pre_Element_constraint", "target_upper_cardinality", 1)
-
-		// Association LHS_contains (LHS, Pre_Element) {}
-		instantiate_link(new_model, "Association", "LHS_contains", "LHS", "Pre_Element")
-		instantiate_attribute(new_model, "LHS_contains", "name", "contains")
-
-		// Association NAC_contains (NAC, Pre_Element) {}
-		//instantiate_link(new_model, "Association", "NAC_contains", "NAC", "Pre_Element")
-		//instantiate_attribute(new_model, "NAC_contains", "name", "contains")
-
-		inheritor = "Pre_Element"
-
-	else:
-		//	Class RHS {
-		//		action : FuncDef {
-		//			target_upper_cardinality = 1
-		//		}
-		//		upper_cardinality = 1
-		//		lower_cardinality = 1
-		//	}
-		instantiate_node(new_model, "Class", "RHS")
-		instantiate_attribute(new_model, "RHS", "lower_cardinality", 1)
-		instantiate_attribute(new_model, "RHS", "upper_cardinality", 1)
-		instantiate_link(new_model, "Association", "RHS_action", "RHS", "funcdef")
-		instantiate_attribute(new_model, "RHS_action", "name", "action")
-		instantiate_attribute(new_model, "RHS_action", "target_upper_cardinality", 1)
-
-		//	Class Post_Element {
-		//		label : String {
-		//			target_lower_cardinality = 1
-		//			target_upper_cardinality = 1
-		//		}
-		//		value : funcdef {
-		//			target_upper_cardinality = 1
-		//		}
-		//		action : funcdef {
-		//			target_upper_cardinality = 1
-		//		}
-		//	}
-		instantiate_node(new_model, "Class", "Post_Element")
-		instantiate_link(new_model, "Association", "Post_Element_label", "Post_Element", "String")
-		instantiate_attribute(new_model, "Post_Element_label", "name", "label")
-		instantiate_attribute(new_model, "Post_Element_label", "target_lower_cardinality", 1)
-		instantiate_attribute(new_model, "Post_Element_label", "target_upper_cardinality", 1)
-		instantiate_link(new_model, "Association", "Post_Element_value", "Post_Element", "funcdef")
-		instantiate_attribute(new_model, "Post_Element_value", "name", "value")
-		instantiate_attribute(new_model, "Post_Element_value", "target_upper_cardinality", 1)
-		instantiate_link(new_model, "Association", "Post_Element_action", "Post_Element", "funcdef")
-		instantiate_attribute(new_model, "Post_Element_action", "name", "action")
-		instantiate_attribute(new_model, "Post_Element_action", "target_upper_cardinality", 1)
-
-		// Association RHS_contains (RHS, Post_Element) {}
-		instantiate_link(new_model, "Association", "RHS_contains", "RHS", "Post_Element")
-		instantiate_attribute(new_model, "RHS_contains", "name", "contains")
-
-		inheritor = "Post_Element"
+	//	Class LHS {
+	//		constraint : funcdef {
+	//			target_upper_cardinality = 1
+	//		}
+	//		upper_cardinality = 1
+	//		lower_cardinality = 1
+	//	}
+	instantiate_node(new_model, "Class", "LHS")
+	instantiate_attribute(new_model, "LHS", "lower_cardinality", 1)
+	instantiate_attribute(new_model, "LHS", "upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "LHS_constraint", "LHS", "funcdef")
+	instantiate_attribute(new_model, "LHS_constraint", "name", "constraint")
+	instantiate_attribute(new_model, "LHS_constraint", "target_upper_cardinality", 1)
+
+	//	Class Pre_Element {
+	//		label : String {
+	//			target_lower_cardinality = 1
+	//			target_upper_cardinality = 1
+	//		}
+	//		constraint : funcdef {
+	//			target_upper_cardinality = 1
+	//		}
+	//	}
+	instantiate_node(new_model, "Class", "Pre_Element")
+	instantiate_link(new_model, "Association", "Pre_Element_label", "Pre_Element", "String")
+	instantiate_attribute(new_model, "Pre_Element_label", "name", "label")
+	instantiate_attribute(new_model, "Pre_Element_label", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "Pre_Element_label", "target_upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "Pre_Element_constraint", "Pre_Element", "funcdef")
+	instantiate_attribute(new_model, "Pre_Element_constraint", "name", "constraint")
+	instantiate_attribute(new_model, "Pre_Element_constraint", "target_upper_cardinality", 1)
+
+	// Association LHS_contains (LHS, Pre_Element) {}
+	instantiate_link(new_model, "Association", "LHS_contains", "LHS", "Pre_Element")
+	instantiate_attribute(new_model, "LHS_contains", "name", "contains")
+
+	//	Class RHS {
+	//		action : FuncDef {
+	//			target_upper_cardinality = 1
+	//		}
+	//		upper_cardinality = 1
+	//		lower_cardinality = 1
+	//	}
+	instantiate_node(new_model, "Class", "RHS")
+	instantiate_attribute(new_model, "RHS", "lower_cardinality", 1)
+	instantiate_attribute(new_model, "RHS", "upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "RHS_action", "RHS", "funcdef")
+	instantiate_attribute(new_model, "RHS_action", "name", "action")
+	instantiate_attribute(new_model, "RHS_action", "target_upper_cardinality", 1)
+
+	//	Class Post_Element {
+	//		label : String {
+	//			target_lower_cardinality = 1
+	//			target_upper_cardinality = 1
+	//		}
+	//		value : funcdef {
+	//			target_upper_cardinality = 1
+	//		}
+	//		action : funcdef {
+	//			target_upper_cardinality = 1
+	//		}
+	//	}
+	instantiate_node(new_model, "Class", "Post_Element")
+	instantiate_link(new_model, "Association", "Post_Element_label", "Post_Element", "String")
+	instantiate_attribute(new_model, "Post_Element_label", "name", "label")
+	instantiate_attribute(new_model, "Post_Element_label", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "Post_Element_label", "target_upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "Post_Element_value", "Post_Element", "funcdef")
+	instantiate_attribute(new_model, "Post_Element_value", "name", "value")
+	instantiate_attribute(new_model, "Post_Element_value", "target_upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "Post_Element_action", "Post_Element", "funcdef")
+	instantiate_attribute(new_model, "Post_Element_action", "name", "action")
+	instantiate_attribute(new_model, "Post_Element_action", "target_upper_cardinality", 1)
+
+	// Association RHS_contains (RHS, Post_Element) {}
+	instantiate_link(new_model, "Association", "RHS_contains", "RHS", "Post_Element")
+	instantiate_attribute(new_model, "RHS_contains", "name", "contains")
 
 	// Basics are added, now we need to add each node and transition, but slightly modified
 	Element keys
 	String key
 	Element new_entry
 	Element entry
-	String append
-	if (is_pre):
-		append = "Pre_"
-	else:
-		append = "Post_"
 
 	keys = dict_keys(old_m)
 	String type_name
@@ -148,23 +126,28 @@ Element function ramify_func(model : Element, prepost : String):
 
 		type_name = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], entry))
 		if (type_name == "Class"):
-			instantiate_node(new_model, type_name, append + key)
+			instantiate_node(new_model, type_name, "Pre_" + key)
+			instantiate_node(new_model, type_name, "Post_" + key)
 
 			// Also make it inherit from the "root element"
-			instantiate_link(new_model, "Inheritance", "", append + key, inheritor)
+			instantiate_link(new_model, "Inheritance", "", "Pre_" + key, "Pre_Element")
+			instantiate_link(new_model, "Inheritance", "", "Post_" + key, "Post_Element")
 
 		elif (type_name == "Association"):
 			old_source = reverseKeyLookup(model["model"], read_edge_src(entry))
 			old_target = reverseKeyLookup(model["model"], read_edge_dst(entry))
-			instantiate_link(new_model, type_name, append + key, append + old_source, append + old_target)
+			instantiate_link(new_model, type_name, "Pre_" + key, "Pre_" + old_source, "Pre_" + old_target)
+			instantiate_link(new_model, type_name, "Post_" + key, "Post_" + old_source, "Post_" + old_target)
 
 			// 1) Make it inherit from the Root Element (Pre_Element or Post_Element)
-			instantiate_link(new_model, "Inheritance", "", append + key, inheritor)
+			instantiate_link(new_model, "Inheritance", "", "Pre_" + key, "Pre_Element")
+			instantiate_link(new_model, "Inheritance", "", "Post_" + key, "Post_Element")
 			
 		elif (type_name == "Inheritance"):
 			old_source = reverseKeyLookup(model["model"], read_edge_src(entry))
 			old_target = reverseKeyLookup(model["model"], read_edge_dst(entry))
-			instantiate_link(new_model, type_name, append + key, append + old_source, append + old_target)
+			instantiate_link(new_model, type_name, "Pre_" + key, "Pre_" + old_source, "Pre_" + old_target)
+			instantiate_link(new_model, type_name, "Post_" + key, "Post_" + old_source, "Post_" + old_target)
 
 		elif (bool_not(has_value(entry))):
 			create_edge(to_link, entry)
@@ -183,21 +166,96 @@ Element function ramify_func(model : Element, prepost : String):
 			old_source = reverseKeyLookup(model["model"], read_edge_src(entry))
 			if (bool_or(bool_or(name == "name", name == "upper_cardinality"), bool_or(name == "source_upper_cardinality", name == "target_upper_cardinality"))):
 				// Keep the old name for the physical attributes!
-				instantiate_attribute(new_model, append + old_source, name, read_edge_dst(entry))
+				instantiate_attribute(new_model, "Pre_" + old_source, name, read_edge_dst(entry))
+				instantiate_attribute(new_model, "Post_" + old_source, name, read_edge_dst(entry))
 			else:
 				// Rename the attributes as well
-				instantiate_attribute(new_model, append + old_source, append + name, read_edge_dst(entry))
+				instantiate_attribute(new_model, "Pre_" + old_source, "Pre_" + name, read_edge_dst(entry))
+				instantiate_attribute(new_model, "Post_" + old_source, "Post_" + name, read_edge_dst(entry))
 
-	return new_model!
+	// Define schedule over these elements
 
-Element function ramify(model : Element):
-	Element rv
-	rv = create_node()
+	//  Class Entry {}
+	instantiate_node(new_model, "Class", "Entry")
+
+	//	Class Success : Entry {}
+	instantiate_node(new_model, "Class", "Success")
+	instantiate_link(new_model, "Inheritance", "", "Success", "Entry")
+
+	//	Class Failure : Entry {}
+	instantiate_node(new_model, "Class", "Failure")
+	instantiate_link(new_model, "Inheritance", "", "Failure", "Entry")
 
-	// Create Pre part
-	dict_add(rv, "pre", ramify_func(model, "pre"))
+	//  Class Rule : Entry {}
+	instantiate_node(new_model, "Class", "Rule")
+	instantiate_link(new_model, "Inheritance", "", "Rule", "Entry")
 
-	// Create Post part
-	dict_add(rv, "post", ramify_func(model, "post"))
+	//  Association OnSuccess(Rule, Entry){
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "OnSuccess", "Rule", "Entry")
+	instantiate_attribute(new_model, "OnSuccess", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "OnSuccess", "target_upper_cardinality", 1)
 
-	return rv!
+	//  Association OnFailure(Rule, Entry){
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "OnFailure", "Rule", "Entry")
+	instantiate_attribute(new_model, "OnFailure", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "OnFailure", "target_upper_cardinality", 1)
+
+	// 	Class Query : Rule {}
+	instantiate_node(new_model, "Class", "Query")
+	instantiate_link(new_model, "Inheritance", "", "Query", "Rule")
+
+	// 	Association QueryLHS (Query, LHS) {
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "QueryLHS", "Query", "LHS")
+	instantiate_attribute(new_model, "QueryLHS", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "QueryLHS", "target_upper_cardinality", 1)
+
+	//	Class Atomic : Rule {}
+	instantiate_node(new_model, "Class", "Atomic")
+	instantiate_link(new_model, "Inheritance", "", "Atomic", "Rule")
+
+	// 	Association AtomicLHS (Atomic, LHS) {
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "AtomicLHS", "Atomic", "LHS")
+	instantiate_attribute(new_model, "AtomicLHS", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "AtomicLHS", "target_upper_cardinality", 1)
+
+	// 	Association AtomicRHS (Atomic, RHS) {
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "AtomicRHS", "Atomic", "RHS")
+	instantiate_attribute(new_model, "AtomicRHS", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "AtomicRHS", "target_upper_cardinality", 1)
+
+	//	Class Composite : Rule {}
+	instantiate_node(new_model, "Class", "Composite")
+	instantiate_link(new_model, "Inheritance", "", "Composite", "Rule")
+
+	//	Association Initial(Composite, Entry){
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "Initial", "Composite", "Entry")
+	instantiate_attribute(new_model, "Initial", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "Initial", "target_upper_cardinality", 1)
+
+	//	Association Contains(Composite, Entry){
+	//		source_upper_cardinality = 1
+	//		target_lower_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "Contains", "Composite", "Entry")
+	instantiate_attribute(new_model, "Contains", "source_upper_cardinality", 1)
+	instantiate_attribute(new_model, "Contains", "target_lower_cardinality", 1)
+
+	return new_model!

+ 117 - 51
bootstrap/transform.alc

@@ -1,8 +1,10 @@
 include "primitives.alh"
 include "object_operations.alh"
 include "modelling.alh"
+include "random.alh"
+include "conformance_scd.alh"
 
-Element function make_matching_schedule(LHS_model : Element):
+Element function make_matching_schedule(schedule_model : Element, LHS : Element):
 	Element schedule
 	Element workset
 	Element all_elements
@@ -11,11 +13,12 @@ Element function make_matching_schedule(LHS_model : Element):
 	String new_element
 	Integer counter
 	String next
+	Element tmp
 
 	// Initialize
 	schedule = create_node()
 	workset = create_node()
-	all_elements = allInstances(LHS_model, "Pre_Element")
+	all_elements = allAssociationDestinations(schedule_model, LHS, "LHS_contains")
 	full_all_elements = set_copy(all_elements)
 	required_size = read_nr_out(all_elements)
 
@@ -25,7 +28,7 @@ Element function make_matching_schedule(LHS_model : Element):
 		// workset is empty, but we still need to add to the list
 		// Therefore, we pick a random, unbound node, and add it to the workset
 		new_element = set_pop(all_elements)
-		while (bool_or(set_in(schedule, new_element), is_edge(LHS_model["model"][new_element]))):
+		while (bool_or(set_in(schedule, new_element), is_edge(schedule_model["model"][new_element]))):
 			// Element is not usable, so pick another one
 			new_element = set_pop(all_elements)
 		set_add(workset, new_element)
@@ -41,21 +44,21 @@ Element function make_matching_schedule(LHS_model : Element):
 					list_append(schedule, next)
 
 					// If it is an edge, we should also add the target and source
-					if (is_edge(LHS_model["model"][next])):
+					if (is_edge(schedule_model["model"][next])):
 						// Add the target/source to the schedule
-						set_add(workset, reverseKeyLookup(LHS_model["model"], read_edge_src(LHS_model["model"][next])))
-						set_add(workset, reverseKeyLookup(LHS_model["model"], read_edge_dst(LHS_model["model"][next])))
+						set_add(workset, reverseKeyLookup(schedule_model["model"], read_edge_src(schedule_model["model"][next])))
+						set_add(workset, reverseKeyLookup(schedule_model["model"], read_edge_dst(schedule_model["model"][next])))
 
 					// Also add all outgoing links
-					counter = read_nr_out(LHS_model["model"][next])
+					counter = read_nr_out(schedule_model["model"][next])
 					while (counter > 0):
 						counter = counter - 1
-						if (set_in_node(LHS_model["model"], read_out(LHS_model["model"][next], counter))):
-							set_add(workset, reverseKeyLookup(LHS_model["model"], read_out(LHS_model["model"][next], counter)))
+						if (set_in_node(schedule_model["model"], read_out(schedule_model["model"][next], counter))):
+							set_add(workset, reverseKeyLookup(schedule_model["model"], read_out(schedule_model["model"][next], counter)))
 
 	return schedule!
 
-Element function get_possible_bindings(host_model : Element, LHS_model : Element, current_element : String, map : Element):
+Element function get_possible_bindings(host_model : Element, schedule_model : Element, current_element : String, map : Element):
 	Element options
 	String src_label
 	String dst_label
@@ -64,13 +67,13 @@ Element function get_possible_bindings(host_model : Element, LHS_model : Element
 
 	options = create_node()
 
-	typename = reverseKeyLookup(LHS_model["metamodel"]["model"], dict_read_node(LHS_model["type_mapping"], LHS_model["model"][current_element]))
+	typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][current_element]))
 	original_typename = string_substr(typename, 4, string_len(typename))
 
-	if (is_edge(LHS_model["model"][current_element])):
+	if (is_edge(schedule_model["model"][current_element])):
 		// Is an edge, so check for already bound source/target
-		src_label = read_attribute(LHS_model, reverseKeyLookup(LHS_model["model"], read_edge_src(LHS_model["model"][current_element])), "label")
-		dst_label = read_attribute(LHS_model, reverseKeyLookup(LHS_model["model"], read_edge_dst(LHS_model["model"][current_element])), "label")
+		src_label = read_attribute(schedule_model, reverseKeyLookup(schedule_model["model"], read_edge_src(schedule_model["model"][current_element])), "label")
+		dst_label = read_attribute(schedule_model, reverseKeyLookup(schedule_model["model"], read_edge_dst(schedule_model["model"][current_element])), "label")
 
 		if (bool_and(set_in(dict_keys(map), src_label), set_in(dict_keys(map), dst_label))):
 			// Source and destination are bound
@@ -105,13 +108,13 @@ Element function get_possible_bindings(host_model : Element, LHS_model : Element
 			// Option is already present with another label, so skip this!
 
 			// Check for local constraints of element
-			if (element_eq(read_attribute(LHS_model, current_element, "constraint"), read_root())):
+			if (element_eq(read_attribute(schedule_model, current_element, "constraint"), read_root())):
 				// No local constraints, so all is well
 				set_add(filtered_options, option)
 			else:
 				// Check local constraints and add only if positive
 				Element constraint_function
-				constraint_function = read_attribute(LHS_model, current_element, "constraint")
+				constraint_function = read_attribute(schedule_model, current_element, "constraint")
 				Boolean result
 				result = constraint_function(host_model, option)
 				if (result):
@@ -119,12 +122,12 @@ Element function get_possible_bindings(host_model : Element, LHS_model : Element
 
 	return filtered_options!
 
-Element function match(host_model : Element, LHS_model : Element):
-	// Match the LHS_model to the host_model, returning all possible mappings from LHS_model elements to host_model elements
+Element function match(host_model : Element, schedule_model : Element, LHS : Element):
+	// Match the schedule_model to the host_model, returning all possible mappings from schedule_model elements to host_model elements
 
 	// Make the schedule first
 	Element schedule
-	schedule = make_matching_schedule(LHS_model)
+	schedule = make_matching_schedule(schedule_model, LHS)
 
 	// Now follow the schedule, incrementally building all mappings
 	Element mappings
@@ -143,24 +146,21 @@ Element function match(host_model : Element, LHS_model : Element):
 
 		while (read_nr_out(mappings) > 0):
 			map = set_pop(mappings)
-			options = get_possible_bindings(host_model, LHS_model, current_element, map)
+			options = get_possible_bindings(host_model, schedule_model, current_element, map)
 
 			while (read_nr_out(options) > 0):
 				option = set_pop(options)
 				new_map = dict_copy(map)
-				dict_add(new_map, read_attribute(LHS_model, current_element, "label"), option)
+				dict_add(new_map, read_attribute(schedule_model, current_element, "label"), option)
 				set_add(new_mappings, new_map)
 
 		mappings = new_mappings
 
 	// Finished, so try the global constraint
-	Element LHS
 	Element constraint
 
 	new_mappings = create_node()
-	LHS = allInstances(LHS_model, "LHS")
-	LHS = set_pop(LHS)
-	constraint = read_attribute(LHS_model, LHS, "constraint")
+	constraint = read_attribute(schedule_model, LHS, "constraint")
 	if (element_neq(constraint, read_root())):
 		while (read_nr_out(mappings) > 0):
 			map = set_pop(mappings)
@@ -170,7 +170,7 @@ Element function match(host_model : Element, LHS_model : Element):
 
 	return mappings!
 
-Void function rewrite(host_model : Element, RHS_model : Element, mapping : Element):
+Void function rewrite(host_model : Element, schedule_model : Element, RHS : String, mapping : Element):
 	// Rewrite the host model based on the mapping combined with the RHS
 	Element LHS_labels
 	Element RHS_labels
@@ -197,10 +197,10 @@ Void function rewrite(host_model : Element, RHS_model : Element, mapping : Eleme
 	RHS_labels = create_node()
 	RHS_map = create_node()
 
-	RHS_elements = allInstances(RHS_model, "Post_Element")
+	RHS_elements = allAssociationDestinations(schedule_model, RHS, "RHS_contains")
 	while (read_nr_out(RHS_elements) > 0):
 		tmp = set_pop(RHS_elements)
-		label = read_attribute(RHS_model, tmp, "label")
+		label = read_attribute(schedule_model, tmp, "label")
 		set_add(RHS_labels, label)
 		dict_add(RHS_map, label, tmp)
 
@@ -219,24 +219,24 @@ Void function rewrite(host_model : Element, RHS_model : Element, mapping : Eleme
 	while (read_nr_out(labels_to_add) > 0):
 		// Add the elements linked to these labels
 		label = list_pop(labels_to_add, 0)
-		if (element_neq(read_attribute(RHS_model, RHS_map[label], "value"), read_root())):
+		if (element_neq(read_attribute(schedule_model, RHS_map[label], "value"), read_root())):
 			// There is a value associated with this node
-			value_function = read_attribute(RHS_model, RHS_map[label], "value")
+			value_function = read_attribute(schedule_model, RHS_map[label], "value")
 			value = value_function(host_model, mapping)
 
-			typename = reverseKeyLookup(RHS_model["metamodel"]["model"], dict_read_node(RHS_model["type_mapping"], RHS_model["model"][RHS_map[label]]))
+			typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][RHS_map[label]]))
 			original_typename = string_substr(typename, 5, string_len(typename))
 			new_name = instantiate_value(host_model, original_typename, "", value)
 			dict_add(new_mapping, label, new_name)
 
-		elif (is_edge(RHS_model["model"][RHS_map[label]])):
+		elif (is_edge(schedule_model["model"][RHS_map[label]])):
 			// Edge
-			src = read_attribute(RHS_model, reverseKeyLookup(RHS_model["model"], read_edge_src(RHS_model["model"][RHS_map[label]])), "label")
-			dst = read_attribute(RHS_model, reverseKeyLookup(RHS_model["model"], read_edge_dst(RHS_model["model"][RHS_map[label]])), "label")
+			src = read_attribute(schedule_model, reverseKeyLookup(schedule_model["model"], read_edge_src(schedule_model["model"][RHS_map[label]])), "label")
+			dst = read_attribute(schedule_model, reverseKeyLookup(schedule_model["model"], read_edge_dst(schedule_model["model"][RHS_map[label]])), "label")
 			// First check whether both source and destination are already created
 			if (bool_and(dict_in(new_mapping, src), dict_in(new_mapping, dst))):
 				// Both are present, so we can make the link
-				typename = reverseKeyLookup(RHS_model["metamodel"]["model"], dict_read_node(RHS_model["type_mapping"], RHS_model["model"][RHS_map[label]]))
+				typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][RHS_map[label]]))
 				original_typename = string_substr(typename, 5, string_len(typename))
 				new_name = instantiate_link(host_model, original_typename, "", new_mapping[src], new_mapping[dst])
 				dict_add(new_mapping, label, new_name)
@@ -246,14 +246,14 @@ Void function rewrite(host_model : Element, RHS_model : Element, mapping : Eleme
 		else:
 			// Node
 			// Create the node and add it
-			typename = reverseKeyLookup(RHS_model["metamodel"]["model"], dict_read_node(RHS_model["type_mapping"], RHS_model["model"][RHS_map[label]]))
+			typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][RHS_map[label]]))
 			original_typename = string_substr(typename, 5, string_len(typename))
 			new_name = instantiate_node(host_model, original_typename, "")
 			dict_add(new_mapping, label, new_name)
 
 	while (read_nr_out(original_RHS_labels) > 0):
 		label = set_pop(original_RHS_labels)
-		action = read_attribute(RHS_model, RHS_map[label], "action")
+		action = read_attribute(schedule_model, RHS_map[label], "action")
 		if (element_neq(action, read_root())):
 			action(host_model, new_mapping[label], mapping)
 
@@ -264,27 +264,93 @@ Void function rewrite(host_model : Element, RHS_model : Element, mapping : Eleme
 		dict_delete(new_mapping, label)
 
 	// Execute global action (whatever it may be)
-	Element RHS
-	RHS = allInstances(RHS_model, "RHS")
-	RHS = set_pop(RHS)
-	action = read_attribute(RHS_model, RHS, "action")
+	action = read_attribute(schedule_model, RHS, "action")
 	if (element_neq(action, read_root())):
 		action(host_model, new_mapping)
 
 	return!
 
-Void function transform(host_model : Element, LHS_model : Element, RHS_model : Element):
-	Element mapping
+Boolean function transform(host_model : Element, schedule_model : Element):
+	// Find initial model
+	Element all_composites
+	String composite
+	String current
+
+	all_composites = allInstances(schedule_model, "Composite")
+	if (read_nr_out(all_composites) == 1):
+		// Only one, so it is easy
+		current = set_pop(all_composites)
+	else:
+		// Filter out those that are themselves contained
+		while (read_nr_out(all_composites) > 0):
+			composite = set_pop(all_composites)
+			if (read_nr_out(allIncomingAssociationInstances(schedule_model, composite, "Contains")) == 0):
+				// Isn't contained in any, so this is the root model!
+				current = composite
+
+	return transform_composite(host_model, schedule_model, current)!
+
+Boolean function transform_composite(host_model : Element, schedule_model : Element, composite : String):
+	String current
+	String typename
+	Boolean result
+
+	current = set_pop(allAssociationDestinations(schedule_model, composite, "Initial"))
+	while (is_nominal_instance(schedule_model, current, "Rule")):
+		log("Exec composite: " + current)
+		// Still a rule that we must execute
+		typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][current]))
+		log("Type: " + typename)
+		if (typename == "Atomic"):
+			result = transform_atomic(host_model, schedule_model, current)
+		elif (typename == "Query"):
+			result = transform_query(host_model, schedule_model, current)
+		elif (typename == "Composite"):
+			result = transform_composite(host_model, schedule_model, current)
+
+		if (result):
+			current = set_pop(allAssociationDestinations(schedule_model, current, "OnSuccess"))
+		else:
+			current = set_pop(allAssociationDestinations(schedule_model, current, "OnFailure"))
+
+	// No longer a rule, so it is either success or failure
+	if (is_nominal_instance(schedule_model, current, "Success")):
+		return True!
+	else:
+		return False!
+
+Boolean function transform_atomic(host_model : Element, schedule_model : Element, current : String):
+	// Execute the atomic transformation
 	Element mappings
+	String LHS
+	Element mapping
+	log("Exec atomic: " + current)
+	LHS = set_pop(allAssociationDestinations(schedule_model, current, "AtomicLHS"))
+	log("Got LHS: " + LHS)
+	mappings = match(host_model, schedule_model, LHS)
+	log("Matched!")
 
-	// Get all possible mappings
-	mappings = match(host_model, LHS_model)
+	if (read_nr_out(mappings) > 0):
+		// Pick one!
+		mapping = random_choice(set_to_list(mappings))
+		String RHS
+		RHS = set_pop(allAssociationDestinations(schedule_model, current, "AtomicRHS"))
+		rewrite(host_model, schedule_model, RHS, mapping)
+		return True!
+	else:
+		return False!
 
-	// Select one such mapping and rewrite it
+Boolean function transform_query(host_model : Element, schedule_model : Element, current : String):
+	// Execute the transformation
+	String LHS
+	Element mappings
+	Element mapping
+	LHS = set_pop(allAssociationDestinations(schedule_model, current, "QueryLHS"))
+	mappings = match(host_model, schedule_model, LHS)
+
+	log("Exec query: " + current)
 	if (read_nr_out(mappings) > 0):
-		// Mapping found, so can rewrite it
-		mapping = set_pop(mappings)
-		rewrite(host_model, RHS_model, mapping)
+		return True!
 	else:
-		output("No mapping found!")
-	return!
+		return False!
+

+ 7 - 14
integration/code/pn_interface.alc

@@ -387,29 +387,22 @@ Element function main():
 			if (dict_in(root, name)):
 				my_model = root[name]
 				result = ramify(my_model)
-				dict_add(root, name + "_PRE", result["pre"])
-				dict_add(root, name + "_POST", result["post"])
+				dict_add(root, name + "_SCHEDULE", result)
 				output("success")
 			else:
 				output("Model not found; aborting")
 		elif (command == "transform"):
 			Element result
-			String lhs
-			String rhs
+			String schedule
 			output("Which model do you want to transform?")
 			name = input()
 			if (dict_in(root, name)):
-				output("Which LHS do you want to match?")
-				lhs = input()
-				if (dict_in(root, lhs)):
-					output("Which RHS do you want to rewrite?")
-					rhs = input()
-					if (dict_in(root, rhs)):
-						transform(root[name], root[lhs], root[rhs])
-					else:
-						output("Unknown RHS selected!")
+				output("Which schedule do you want to execute?")
+				schedule = input()
+				if (dict_in(root, schedule)):
+					output("Transformation result: " + cast_v2s(transform(root[name], root[schedule])))
 				else:
-					output("Unknown LHS selected!")
+					output("Unknown transformation selected!")
 			else:
 				output("Unknown host model selected!")
 		else:

+ 60 - 22
integration/test_pn_interface.py

@@ -33,6 +33,7 @@ all_files = [   "pn_interface.alc",
                 "transform.alc",
                 "ramify.alc",
                 "metamodels.alc",
+                "random.alc",
                 "constructors.alc",
                 "modelling.alc",
                 "compilation_manager.alc",
@@ -538,7 +539,7 @@ Element function constraint(model : Element, name : String):
             mode))
 
     def test_po_pn_interface_transform_pn(self):
-        constraint_code = \
+        constraint_mark_code = \
             """
 include "primitives.alh"
 include "modelling.alh"
@@ -546,19 +547,21 @@ include "object_operations.alh"
 Boolean function constraint(host_model : Element, name : String):
 \t// Make sure that all places have enough tokens
 \tElement links
-\tElement link
-\tElement place
+\tString link
+\tString place
 \tlinks = allIncomingAssociationInstances(host_model, name, "P2T")
 \twhile (read_nr_out(links) > 0):
 \t\tlink = set_pop(links)
 \t\tplace = readAssociationSource(host_model, link)
+\t\tlog("Check link " + link)
+\t\tlog("Check place " + place)
 \t\tif (integer_lt(read_attribute(host_model, place, "tokens"), read_attribute(host_model, link, "weight"))):
 \t\t\t// Not enough tokens for this weight
 \t\t\treturn False!
 \treturn True!
             """
 
-        action_code = \
+        action_mark_code = \
             """
 include "primitives.alh"
 include "modelling.alh"
@@ -568,8 +571,33 @@ Void function action(host_model : Element, name : String, mapping : Element):
 \treturn!
             """
 
-        constructor_action = get_constructor(action_code)
-        constructor_constraint = get_constructor(constraint_code)
+        constraint_consume_code = \
+            """
+include "primitives.alh"
+include "modelling.alh"
+Boolean function constraint(host_model : Element, name : String):
+\t// Check if this node is executing currently
+\treturn value_eq(read_attribute(host_model, name, "executing"), True)!
+            """
+
+        action_consume_code = \
+            """
+include "primitives.alh"
+include "modelling.alh"
+Void function action(host_model : Element, name : String, mapping : Element):
+\tInteger tokens
+\tInteger weight
+\ttokens = read_attribute(host_model, name, "tokens")
+\tweight = read_attribute(host_model, mapping["2"], "weight")
+\tunset_attribute(host_model, name, "tokens")
+\tinstantiate_attribute(host_model, name, "tokens", tokens - weight)
+\treturn!
+            """
+
+        constructor_mark_action = get_constructor(action_mark_code)
+        constructor_mark_constraint = get_constructor(constraint_mark_code)
+        constructor_consume_constraint = get_constructor(constraint_consume_code)
+        constructor_consume_action = get_constructor(action_consume_code)
 
         self.assertTrue(run_file(all_files,
             ["new", "SimpleClassDiagrams", "PetriNets_runtime",
@@ -596,28 +624,39 @@ Void function action(host_model : Element, name : String, mapping : Element):
                 "instantiate", "Transition", "t1",
                 "attr_add", "t1", "executing", False,
                 "instantiate", "P2T", "p2t", "p1", "t1",
-                "attr_add", "p2t", "weight", 2,
+                "attr_add", "p2t", "weight", 1,
                 "instantiate", "P2T", "p2t2", "p2", "t1",
                 "attr_add", "p2t2", "weight", 1,
                 "exit",
              "ramify", "PetriNets_runtime",
-             "new", "PetriNets_runtime_PRE", "pn_LHS",
+             # Rule 1: mark transition to execute
+             "new", "PetriNets_runtime_SCHEDULE", "pn_simulate",
                 "instantiate", "LHS", "lhs",
-                "instantiate", "Pre_Transition", "t",
-                "attr_add", "t", "label", "0",
-                #"attr_add_code", "t", "constraint", 
-            #] + constructor_constraint + [
-                "instantiate", "LHS_contains", "", "lhs", "t",
-                "exit",
-             "new", "PetriNets_runtime_POST", "pn_RHS",
+                "instantiate", "Pre_Transition", "pre_t",
+                "attr_add", "pre_t", "label", "0",
+                "attr_add_code", "pre_t", "constraint", 
+            ] + constructor_mark_constraint + [
+                "instantiate", "LHS_contains", "", "lhs", "pre_t",
                 "instantiate", "RHS", "rhs",
-                "instantiate", "Post_Transition", "t",
-                "attr_add", "t", "label", "0",
-                "attr_add_code", "t", "action",
-            ] + constructor_action + [
-                "instantiate", "RHS_contains", "", "rhs", "t",
+                "instantiate", "Post_Transition", "post_t",
+                "attr_add", "post_t", "label", "0",
+                "attr_add_code", "post_t", "action",
+            ] + constructor_mark_action + [
+                "instantiate", "RHS_contains", "", "rhs", "post_t",
+                "instantiate", "Composite", "main",
+                "instantiate", "Atomic", "mark",
+                "instantiate", "AtomicLHS", "", "mark", "lhs",
+                "instantiate", "AtomicRHS", "", "mark", "rhs",
+                "instantiate", "Success", "success",
+                "instantiate", "Failure", "failure",
+                "instantiate", "Contains", "", "main", "mark",
+                "instantiate", "Contains", "", "main", "success",
+                "instantiate", "Contains", "", "main", "failure",
+                "instantiate", "OnSuccess", "", "mark", "success",
+                "instantiate", "OnFailure", "", "mark", "failure",
+                "instantiate", "Initial", "", "main", "mark",
                 "exit",
-             "transform", "pn", "pn_LHS", "pn_RHS",
+             "transform", "pn", "pn_simulate",
              "load", "pn",
                 "list",
                 "verify",
@@ -626,4 +665,3 @@ Void function action(host_model : Element, name : String, mapping : Element):
                 "exit",
                 ],
             None, "PO"))
-

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

@@ -10,3 +10,4 @@ String function print_dict(dict : Element)
 String function readAssociationSource(model : Element, name : String)
 String function readAssociationDestination(model : Element, name : String)
 String function followAssociation(model : Element, element_name : String, association_name : String)
+Element function allAssociationDestinations(model : Element, name : String, association_type : String)

+ 1 - 2
interface/HUTN/includes/transform.alh

@@ -1,2 +1 @@
-Element function make_matching_schedule(LHS_model : Element)
-Void function transform(host_model : Element, LHS_model : Element, RHS_model : Element)
+Boolean function transform(host_model : Element, schedule_model : Element)