Browse Source

Modification of CBDs at runtime is now possible

Yentl Van Tendeloo 8 years ago
parent
commit
646690deea

BIN
bootstrap/bootstrap.m.gz


+ 5 - 0
integration/code/cbd_runtime.mvc

@@ -49,6 +49,11 @@ SCD CausalBlockDiagrams_Runtime{
         lower_cardinality = 1
         upper_cardinality = 1
 
+        start_time : Natural {
+            target_lower_cardinality = 1
+            target_upper_cardinality = 1
+        }
+
         current_time : Natural {
             target_lower_cardinality = 1
             target_upper_cardinality = 1

+ 82 - 30
integration/code/cbd_semantics.alc

@@ -3,6 +3,7 @@ include "modelling.alh"
 include "object_operations.alh"
 include "library.alh"
 include "conformance_scd.alh"
+include "mini_modify.alh"
 
 Void function main():
 	Element model
@@ -20,11 +21,12 @@ Void function main():
 			verify_result = conformance_scd(model)
 			if (verify_result == "OK"):
 				output("Model OK!")
+				log("Model conforms!")
 				execute_cbd(model)
 			else:
 				output("Non-conforming model: " + verify_result)
 
-Element function translate_to_runtime(design_model : Element):
+Element function retype_to_runtime(design_model : Element):
 	Element runtime_model
 	Element all_blocks
 	Element all_links
@@ -47,9 +49,6 @@ Element function translate_to_runtime(design_model : Element):
 		element_name = instantiate_node(runtime_model, mm_type_name, element_name)
 		if (mm_type_name == "ConstantBlock"):
 			instantiate_attribute(runtime_model, element_name, "value", read_attribute(design_model, element_name, "value"))
-		elif (mm_type_name == "DelayBlock"):
-			instantiate_attribute(runtime_model, element_name, "memory", 0.0)
-		instantiate_attribute(runtime_model, element_name, "signal", 0.0)
 
 	// Don't merge this together with the block conversion, as the destination block might not exist yet!
 	all_links = allInstances(design_model, "Link")
@@ -66,17 +65,52 @@ Element function translate_to_runtime(design_model : Element):
 		dst = reverseKeyLookup(design_model["model"], read_edge_dst(design_model["model"][element_name]))
 		instantiate_link(runtime_model, "InitialCondition", element_name, src, dst)
 
-	create_schedule(runtime_model, True)
+	return runtime_model!
 
-	create_schedule(runtime_model, False)
+Element function sanitize(new_runtime_model : Element, old_runtime_model : Element):
+	Element all_blocks
+	Element all_links
+	String mm_type_name
+	String element_name
+	String attr_name
+	String attr_value
+	String attribute
+	String time
+	Element all_attributes
+	Integer current_time
+	Integer termination_time
 
-	time = instantiate_node(runtime_model, "Time", "time")
-	instantiate_attribute(runtime_model, time, "current_time", 0)
-	instantiate_attribute(runtime_model, time, "termination_time", 100)
+	all_blocks = allInstances(new_runtime_model, "Block")
+	while (list_len(all_blocks) > 0):
+		element_name = set_pop(all_blocks)
+		mm_type_name = reverseKeyLookup(new_runtime_model["metamodel"]["model"], dict_read_node(new_runtime_model["type_mapping"], new_runtime_model["model"][element_name]))
+		if (dict_in(old_runtime_model["model"], element_name)):
+			if (mm_type_name == "DelayBlock"):
+				instantiate_attribute(new_runtime_model, element_name, "memory", read_attribute(old_runtime_model, element_name, "memory"))
+			instantiate_attribute(new_runtime_model, element_name, "signal", read_attribute(old_runtime_model, element_name, "signal"))
+		else:
+			if (mm_type_name == "DelayBlock"):
+				instantiate_attribute(new_runtime_model, element_name, "memory", 0.0)
+			instantiate_attribute(new_runtime_model, element_name, "signal", 0.0)
 
-	return runtime_model!
+	if (dict_in(old_runtime_model["model"], "time")):
+		current_time = read_attribute(old_runtime_model, "time", "current_time")
+		termination_time = read_attribute(old_runtime_model, "time", "termination_time")
+	else:
+		current_time = 0
+		termination_time = 10
+
+	create_schedule(new_runtime_model, old_runtime_model, current_time)
+	create_schedule(new_runtime_model, old_runtime_model, -1)
+
+	time = instantiate_node(new_runtime_model, "Time", "time")
+	instantiate_attribute(new_runtime_model, time, "start_time", current_time)
+	instantiate_attribute(new_runtime_model, time, "current_time", current_time)
+	instantiate_attribute(new_runtime_model, time, "termination_time", termination_time)
+
+	return new_runtime_model!
 
-Void function create_schedule(model : Element, is_time_zero : Boolean):
+Void function create_schedule(model : Element, old_model : Element, start_time : Integer):
 	Element all_blocks
 	Element visited
 	Element to_visit
@@ -91,7 +125,7 @@ Void function create_schedule(model : Element, is_time_zero : Boolean):
 	all_blocks = allInstances(model, "Block")
 	visited = create_node()
 	to_visit = create_node()
-	if (is_time_zero):
+	if (start_time != -1):
 		schedule = instantiate_node(model, "Schedule", "schedule_init")
 	else:
 		schedule = instantiate_node(model, "Schedule", "schedule_run")
@@ -104,10 +138,10 @@ Void function create_schedule(model : Element, is_time_zero : Boolean):
 		while (list_len(to_visit) > 0):
 			element_name = list_read(to_visit, list_len(to_visit) - 1)
 			if (reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][element_name])) == "DelayBlock"):
-				if (is_time_zero):
-					incoming_links = allIncomingAssociationInstances(model, element_name, "InitialCondition")
-				else:
+				if (dict_in(old_model["model"], element_name)):
 					incoming_links = create_node()
+				else:
+					incoming_links = allIncomingAssociationInstances(model, element_name, "InitialCondition")
 			else:
 				incoming_links = allIncomingAssociationInstances(model, element_name, "Link")
 			ready = True
@@ -155,14 +189,14 @@ Void function list_CBD(model : Element):
 		elem = set_pop(all_elements)
 		output((("    " + reverseKeyLookup(model["model"], read_edge_src(model["model"][elem]))) + " --> ") + reverseKeyLookup(model["model"], read_edge_dst(model["model"][elem])))
 
-	output("Schedule (== 0):")
+	output(("Schedule (t = " + cast_v2s(read_attribute(model, "time", "start_time"))) + "):")
 	elem = "schedule_init"
 	while (read_nr_out(allOutgoingAssociationInstances(model, elem, "LinkedBlock")) > 0):
 		block = readAssociationDestination(model, set_pop(allOutgoingAssociationInstances(model, elem, "LinkedBlock")))
 		output("    " + block)
 		elem = readAssociationDestination(model, set_pop(allOutgoingAssociationInstances(model, elem, "NextSchedule")))
 
-	output("Schedule (> 0):")
+	output(("Schedule (t > " + cast_v2s(read_attribute(model, "time", "start_time"))) + "):")
 	elem = "schedule_run"
 	while (read_nr_out(allOutgoingAssociationInstances(model, elem, "LinkedBlock")) > 0):
 		block = readAssociationDestination(model, set_pop(allOutgoingAssociationInstances(model, elem, "LinkedBlock")))
@@ -184,7 +218,7 @@ Void function step_simulation(model : Element):
 	Element delay_blocks
 
 	time = "time"
-	if (cast_s2i(cast_v2s(read_attribute(model, time, "current_time"))) == 0):
+	if (read_attribute(model, time, "current_time") == read_attribute(model, time, "start_time")):
 		schedule = "schedule_init"
 	else:
 		schedule = "schedule_run"
@@ -206,7 +240,7 @@ Void function step_simulation(model : Element):
 				selected = readAssociationSource(model, set_pop(incoming))
 				signal = signal + cast_s2f(cast_v2s(read_attribute(model, selected, "signal")))
 		elif (blocktype == "MultiplyBlock"):
-			signal = 0.0
+			signal = 1.0
 			incoming = allIncomingAssociationInstances(model, block, "Link")
 			while (read_nr_out(incoming) > 0):
 				selected = readAssociationSource(model, set_pop(incoming))
@@ -259,15 +293,21 @@ Void function set_termination_time(model : Element):
 	instantiate_attribute(model, "time", "termination_time", input())
 	return !
 
-Void function execute_cbd(model : Element):
+Void function execute_cbd(design_model : Element):
 	String verify_result
-	model = translate_to_runtime(model)
-	output("Runtime model constructed OK!")
-
+	Element runtime_model
+	Element old_runtime_model
 	String cmd
 	Boolean running
-	running = False
 
+	log("New model")
+	old_runtime_model = instantiate_model(import_node("models/CausalBlockDiagrams_Runtime"))
+	log("Retype")
+	runtime_model = retype_to_runtime(design_model)
+	log("Sanitize")
+	runtime_model = sanitize(runtime_model, old_runtime_model)
+	log("Finished")
+	running = False
 	while (True):
 		if (running):
 			if (has_input()):
@@ -283,7 +323,7 @@ Void function execute_cbd(model : Element):
 			if (bool_not(running)):
 				output("  step    -- do one simulation step")
 				output("  start   -- start simulation")
-				//output("  modify  -- live modelling: modify model structure")
+				output("  modify  -- live modelling: modify model structure")
 				output("  list    -- list blocks and connections")
 				output("  exit    -- select another model")
 				output("  verify  -- verify the runtime model")
@@ -293,9 +333,9 @@ Void function execute_cbd(model : Element):
 			output("  term    -- set termination time")
 		elif (cmd == "step"):
 			// Do a simulation step
-			step_simulation(model)
+			step_simulation(runtime_model)
 		elif (cmd == "term"):
-			set_termination_time(model)
+			set_termination_time(runtime_model)
 		elif (running):
 			if (cmd == "pause"):
 				running = False
@@ -305,13 +345,25 @@ Void function execute_cbd(model : Element):
 		else:
 			// Not running
 			if (cmd == "list"):
-				list_CBD(model)
+				list_CBD(runtime_model)
 			elif (cmd == "start"):
 				running = True
 			elif (cmd == "exit"):
 				return!
+			elif (cmd == "modify"):
+				verify_result = "init"
+				while (verify_result != "OK"):
+					modify(design_model)
+					verify_result = conformance_scd(design_model)
+					if (verify_result != "OK"):
+						output("Error in design model: " + verify_result)
+				output("Successfully made modifications to design model!")
+
+				old_runtime_model = runtime_model
+				runtime_model = retype_to_runtime(design_model)
+				runtime_model = sanitize(runtime_model, old_runtime_model)
 			elif (cmd == "verify"):
-				verify_result = conformance_scd(model)
+				verify_result = conformance_scd(runtime_model)
 				if (verify_result != "OK"):
 					output("Error in runtime model: " + verify_result)
 				else:
@@ -320,5 +372,5 @@ Void function execute_cbd(model : Element):
 				output("Did not understand command!")
 				output("Use 'help' for a list of available options")
 
-		if (cast_s2i(cast_v2s(read_attribute(model, "time", "current_time"))) > cast_s2i(cast_v2s(read_attribute(model, "time", "termination_time")))):
+		if (cast_s2i(cast_v2s(read_attribute(runtime_model, "time", "current_time"))) > cast_s2i(cast_v2s(read_attribute(runtime_model, "time", "termination_time")))):
 			running = False

+ 252 - 0
integration/code/mini_modify.alc

@@ -0,0 +1,252 @@
+include "primitives.alh"
+include "constructors.alh"
+include "object_operations.alh"
+include "library.alh"
+include "conformance_scd.alh"
+include "io.alh"
+include "metamodels.alh"
+include "modelling.alh"
+include "compilation_manager.alh"
+
+Element function modify(model : Element):
+	String cmd
+
+	Element attr_list_pn
+	Element attr_keys_pn
+	String attr_key_pn
+	Element metamodel_element_pn
+	String typename
+
+	output("Model loaded, ready for commands!")
+	output("Use 'help' command for a list of possible commands")
+
+	while (True):
+		output("Please give your command.")
+		cmd = input()
+		if (cmd == "help"):
+			output("Generic model operations:")
+			output("  instantiate -- Create a new model element")
+			output("  delete      -- Delete an existing element")
+			output("  attr_add    -- Add an attribute to an element")
+			output("  attr_del    -- Delete an attribute of an element")
+			output("  constrain   -- Add a constraint function to the model")
+			output("  rename      -- Rename an existing element")
+			output("  modify      -- Modify the attributes of an element")
+			output("  list        -- Prints the list of elements in the model")
+			output("  types       -- Prints the list of elements that can be instantiated")
+			output("  read        -- Prints the current state of a model element")
+			output("  verify      -- Check whether the model conforms to the metamodel")
+			output("  retype      -- Change the type of an element")
+			output("  exit        -- Leave the modification interface")
+		elif (cmd == "exit"):
+			return model!
+		elif (cmd == "instantiate"):
+			String mm_type_name
+			output("Type to instantiate?")
+			mm_type_name = input()
+			if (dict_in(model["metamodel"]["model"], mm_type_name)):
+				String element_name
+				output("Name of new element?")
+				element_name = input()
+				if (dict_in(model["model"], element_name)):
+					output("Element already exists; aborting")
+				else:
+					if (is_edge(model["metamodel"]["model"][mm_type_name])):
+						output("Source name?")
+						String src_name
+						src_name = input()
+						if (dict_in(model["model"], src_name)):
+							output("Destination name?")
+							String dst_name
+							dst_name = input()
+							if (dict_in(model["model"], dst_name)):
+								instantiate_link(model, mm_type_name, element_name, src_name, dst_name)
+								output("Instantiation successful!")
+							else:
+								output("Unknown destination; aborting")
+						else:
+							output("Unknown source; aborting")
+					else:
+						instantiate_node(model, mm_type_name, element_name)
+						output("Instantiation successful!")
+			else:
+				output("Unknown type specified; aborting")
+		elif (cmd == "set_inheritance"):
+			String inh_name
+
+			output("Which link in the metamodel is the inheritance link?")
+			inh_name = input()
+
+			if (dict_in(model["metamodel"]["model"], inh_name)):
+				dict_add(model, "inheritance", model["metamodel"]["model"][inh_name])
+				output("Set inheritance link!")
+			else:
+				output("Element not found in metamodel; aborting")
+
+		elif (cmd == "constrain"):
+			output("Element to constrain (empty for global)?")
+			String model_name
+			model_name = input()
+
+			if (model_name == ""):
+				// Global constraint
+				output("Give input to function constructors for GLOBAL constraint!")
+				set_model_constraints(model, construct_function())
+			elif (dict_in(model["model"], model_name)):
+				// Local constraint for this model
+				output("Give input to function constructors for LOCAL constraint!")
+				add_constraint(model, model_name, construct_function())
+				output("Added constraint to model!")
+			else:
+				// Local constraint, but model not found
+				output("Unknown model; aborting")
+		elif (cmd == "modify"):
+			String model_name
+			output("Element to modify?")
+			model_name = input()
+			if (dict_in(model["model"], model_name)):
+				Element attrs
+				attrs = getAttributeList(model, model_name)
+				String attr_name
+				output("Attribute to modify?")
+				attr_name = input()
+				if (set_in(dict_keys(attrs), attr_name)):
+					output("New value?")
+					unset_attribute(model, model_name, attr_name)
+					instantiate_attribute(model, model_name, attr_name, input())
+					output("Modified!")
+				else:
+					output("No such attribute!")
+			else:
+				output("No such model!")
+		elif (cmd == "attr_add"):
+			String model_name
+			output("Which model do you want to assign an attribute to?")
+			model_name = input()
+			if (dict_in(model["model"], model_name)):
+				Element attrs
+				attrs = getAttributeList(model, model_name)
+				String attr_name
+				output("Which attribute do you wish to assign?")
+				attr_name = input()
+				if (set_in(dict_keys(attrs), attr_name)):
+					output("Value of attribute?")
+					instantiate_attribute(model, model_name, attr_name, input())
+					output("Added attribute!")
+				else:
+					output("No such attribute!")
+			else:
+				output("No such model!")
+		elif (cmd == "attr_del"):
+			String model_name
+			output("Which model do you want to remove an attribute of?")
+			model_name = input()
+			if (dict_in(model["model"], model_name)):
+				Element attrs
+				attrs = getAttributeList(model, model_name)
+				String attr_name
+				output("Which attribute do you want to delete?")
+				attr_name = input()
+				if (set_in(dict_keys(attrs), attr_name)):
+					unset_attribute(model, model_name, attr_name)
+					output("Attribute deleted!")
+				else:
+					output("No such attribute!")
+			else:
+				output("No such model!")
+		elif (cmd == "delete"):
+			output("What is the name of the element you want to delete?")
+			cmd = input()
+			if (dict_in(model["model"], cmd)):
+				model_delete_element(model, cmd)
+				output("Deleted!")
+			else:
+				output("No such element; aborting")
+		elif (cmd == "rename"):
+			output("Old name?")
+			String old_name_e
+			old_name_e = input()
+			if (dict_in(model["model"], old_name_e)):
+				output("New name?")
+				String new_name_e
+				new_name_e = input()
+				if (dict_in(model["model"], new_name_e)):
+					output("New name already used; aborting")
+				else:
+					dict_add(model["model"], new_name_e, model["model"][old_name_e])
+					dict_delete(model["model"], old_name_e)
+					output("Rename complete!")
+			else:
+				output("Unknown element; aborting")
+		elif (cmd == "list"):
+			Element keys_m
+			keys_m = dict_keys(model["model"])
+			output("List of all elements:")
+			String v_m
+			while (read_nr_out(keys_m) > 0):
+				v_m = set_pop(keys_m)
+				// Filter out anonymous objects
+				if (bool_not(string_startswith(v_m, "__"))):
+					typename = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][v_m]))
+					output((("  " + v_m) + " : ") + typename)
+		elif (cmd == "read"):
+			output("Element to read?")
+			cmd = input()
+			if (dict_in(model["model"], cmd)):
+				Element read_elem
+				read_elem = model["model"][cmd]
+				metamodel_element_pn = dict_read_node(model["type_mapping"], read_elem)
+
+				output("Name: " + cmd)
+				output("Type: " + reverseKeyLookup(model["metamodel"]["model"], metamodel_element_pn))
+				if (is_edge(read_elem)):
+					output("Source: " + reverseKeyLookup(model["model"], read_edge_src(read_elem)))
+					output("Destination: " + reverseKeyLookup(model["model"], read_edge_dst(read_elem)))
+				if (cast_v2s(read_elem) != "None"):
+					output("Value: " + cast_v2s(read_elem))
+				output("Defines attributes:")
+				attr_list_pn = getInstantiatableAttributes(model, read_elem)
+				attr_keys_pn = dict_keys(attr_list_pn)
+				while (0 < read_nr_out(attr_keys_pn)):
+					attr_key_pn = set_pop(attr_keys_pn)
+					output(((("  " + attr_key_pn) + " : ") + cast_v2s(attr_list_pn[attr_key_pn])))
+				output("Attributes:")
+				attr_list_pn = getAttributeList(model, cmd)
+				attr_keys_pn = dict_keys(attr_list_pn)
+				while (0 < read_nr_out(attr_keys_pn)):
+					attr_key_pn = set_pop(attr_keys_pn)
+					output((((("  " + cast_v2s(attr_key_pn)) + " : ") + cast_v2s(attr_list_pn[attr_key_pn])) + " = ") + cast_v2s(read_attribute(model, reverseKeyLookup(model["model"], read_elem), attr_key_pn)))
+			else:
+				output("Unknown element; aborting")
+		elif (cmd == "verify"):
+			output(conformance_scd(model))
+		elif (cmd == "types"):
+			Element keys_t
+			keys_t = dict_keys(model["metamodel"]["model"])
+			output("List of types:")
+			String v_t
+			while (read_nr_out(keys_t) > 0):
+				v_t = set_pop(keys_t)
+				if (bool_not(string_startswith(v_t, "__"))):
+					output(string_join(("  " + v_t) + " : ", reverseKeyLookup(model["metamodel"]["metamodel"]["model"], dict_read_node(model["metamodel"]["type_mapping"], model["metamodel"]["model"][v_t]))))
+		elif (cmd == "retype"):
+			output("Element to retype?")
+			String elementname
+			elementname = input()
+			if (dict_in(model["model"], elementname)):
+				output("New type")
+				typename = input()
+				if (dict_in(model["metamodel"]["model"], typename)):
+					// OK, do the retyping
+					// First try removing the previous type if it exists
+					dict_delete_node(model["type_mapping"], model["model"][elementname])
+					// Now add the new type
+					dict_add(model["type_mapping"], model["model"][elementname], model["metamodel"]["model"][typename])
+					output("Retyped!")
+				else:
+					output("Unknown type; aborting")
+			else:
+				output("Unknown element; aborting")
+		else:
+			output("Unknown command: " + cast_v2s(cmd))
+			output("Use command 'help' to get a list of available commands")

+ 1 - 0
integration/code/mini_modify.alh

@@ -0,0 +1 @@
+Element function modify(model : Element)