Browse Source

First step towards Strongly Connected Components

Yentl Van Tendeloo 8 years ago
parent
commit
70a1692707
1 changed files with 133 additions and 46 deletions
  1. 133 46
      integration/code/cbd_semantics.alc

+ 133 - 46
integration/code/cbd_semantics.alc

@@ -89,55 +89,138 @@ Element function sanitize(new_runtime_model : Element, old_runtime_model : Eleme
 
 
 	return new_runtime_model!
 	return new_runtime_model!
 
 
-Element function create_schedule(model : Element, start_time : Float):
-	Element all_blocks
-	Element visited
-	Element to_visit
-	Element incoming_links
+Element function create_schedule(model : Element):
+	// Create nice graph first
+	Element nodes
+	Element successors
 	String element_name
 	String element_name
-	String link
-	String source
-	String new_schedule
-	Boolean ready
-	Element schedule
-
-	// TODO add algebraic loop detection (not solution...)
+	Element incoming_links
+	Element all_blocks
 
 
-	schedule = create_node()
-	all_blocks = allInstances(model, "Block")
-	visited = create_node()
-	to_visit = create_node()
+	nodes = allInstances(model, "Block")
+	successors = create_node()
+	while (read_nr_out(nodes) > 0):
+		element_name = set_pop(nodes)
+		if (bool_not(dict_in(successors, element_name))):
+			dict_add(successors, element_name, create_node())
 
 
-	while (read_nr_out(all_blocks) > 0):
-		element_name = set_pop(all_blocks)
-		if (bool_not(set_in(visited, element_name))):
-			list_append(to_visit, element_name)
-
-		while (list_len(to_visit) > 0):
-			element_name = list_read(to_visit, list_len(to_visit) - 1)
-			if (is_nominal_instance(model, element_name, "ICBlock")):
-				if (element_eq(read_attribute(model, element_name, "last_in"), read_root())):
-					incoming_links = allIncomingAssociationInstances(model, element_name, "InitialCondition")
-				else:
-					incoming_links = create_node()
+		if (is_nominal_instance(model, element_name, "ICBlock")):
+			if (element_eq(read_attribute(model, element_name, "last_in"), read_root())):
+				incoming_links = allIncomingAssociationInstances(model, element_name, "InitialCondition")
 			else:
 			else:
-				incoming_links = allIncomingAssociationInstances(model, element_name, "Link")
-			ready = True
+				incoming_links = create_node()
+			if (is_nominal_instance(model, element_name, "DerivatorBlock")):
+				Element new_incoming_links
+				new_incoming_links = allIncomingAssociationInstances(model, element_name, "Link")
+				while (read_nr_out(new_incoming_links) > 0):
+					list_append(incoming_links, set_pop(new_incoming_links))
+		else:
+			incoming_links = allIncomingAssociationInstances(model, element_name, "Link")
+
+		while (read_nr_out(incoming_links) > 0):
+			String source
+			source = readAssociationSource(model, set_pop(incoming_links))
+			if (bool_not(dict_in(successors, source))):
+				dict_add(successors, source, create_node())
+			set_add(successors[source], element_name)
+	
+	Element values
+	values = create_node()
+	dict_add(values, "S", create_node())
+	dict_add(values, "index", 0)
+	dict_add(values, "indices", create_node())
+	dict_add(values, "lowlink", create_node())
+	dict_add(values, "onStack", create_node())
+	dict_add(values, "successors", successors)
+	dict_add(values, "SCC", create_node())
+
+	nodes = allInstances(model, "Block")
+	while (read_nr_out(nodes) > 0):
+		strongconnect(set_pop(nodes), values)
+
+	log("Computed SCC!")
+	log("Print list:")
+	Integer i
+	Integer j
+	Element lst
+	i = 0
+	while (i < read_nr_out(values["SCC"])):
+		log("[")
+		lst = list_read(values["SCC"], i)
+		j = 0
+		while (j < read_nr_out(lst)):
+			log("    " + cast_v2s(list_read(lst, j)))
+			j = j + 1
+		log("]")
+		i = i + 1
+	log("=== END")
+	return values["SCC"]!
+
+Void function dict_overwrite(d : Element, key : Element, value : Element):
+	if (dict_in(d, key)):
+		dict_delete(d, key)
+	if (dict_in_node(d, key)):
+		dict_delete_node(d, key)
+	dict_add(d, key, value)
+
+	return !
+
+Integer function min(a : Integer, b : Integer):
+	if (a < b):
+		return a!
+	else:
+		return b!
 
 
-			while (list_len(incoming_links) > 0):
-				link = set_pop(incoming_links)
-				source = readAssociationSource(model, link)
-				if (bool_not(set_in(visited, source))):
-					list_append(to_visit, source)
-					ready = False
+Void function strongconnect(v : String, values : Element):
+	if (dict_in(values["indices"], v)):
+		return!
+	log("Compute strong connected components")
+	log("Source: " + v)
 
 
-			if (ready):
-				list_append(schedule, element_name)
-				list_delete(to_visit, list_len(to_visit) - 1)
-				set_add(visited, element_name)
+	dict_overwrite(values["indices"], v, values["index"])
+	dict_overwrite(values["lowlink"], v, values["index"])
+	dict_overwrite(values, "index", cast_s2i(cast_v2s(values["index"])) + 1)
 
 
-	log("Schedule length: " + cast_v2s(read_nr_out(schedule)))
-	return schedule!
+	list_append(values["S"], v)
+	dict_overwrite(values["onStack"], v, True)
+	
+	Element successors
+	String w
+	successors = values["successors"][v]
+	while (read_nr_out(successors) > 0):
+		w = set_pop(successors)
+		log("Found successor " + w)
+		if (bool_not(dict_in(values["indices"], w))):
+			strongconnect(w, values)
+			log("Old lowlink: " + cast_v2s(values["lowlink"][v]))
+			dict_overwrite(values["lowlink"], v, min(values["lowlink"][v], values["lowlink"][w]))
+			log("Set lowlink of " + v)
+			log("   to " + cast_v2s(values["lowlink"][v]))
+		elif (dict_in(values["onStack"], w)):
+			if (values["onStack"][w]):
+				dict_overwrite(values["lowlink"], v, min(values["lowlink"][v], values["indices"][w]))
+	
+	if (value_eq(values["lowlink"][v], values["indices"][v])):
+		Element scc
+		scc = create_node()
+		// It will always differ now
+		w = list_pop(values["S"])
+		list_append(scc, w)
+		while (w != v):
+			w = list_pop(values["S"])
+			list_append(scc, w)
+			dict_overwrite(values["onStack"], w, False)
+		list_insert(values["SCC"], scc, 0)
+
+	return!
+
+Element function list_pop(list : Element):
+	Integer top
+	Element t
+	top = list_len(list) - 1
+	t = list_read(list, top)
+	list_delete(list, top)
+	return t!
 
 
 String function readType(model : Element, name : String):
 String function readType(model : Element, name : String):
 	return reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][name]))!
 	return reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][name]))!
@@ -274,8 +357,8 @@ Void function execute_cbd(design_model : Element):
 	else:
 	else:
 		output("CONFORMANCE_FAIL")
 		output("CONFORMANCE_FAIL")
 
 
-	schedule_init = create_schedule(runtime_model, read_attribute(runtime_model, "time", "start_time"))
-	schedule_run = create_schedule(runtime_model, -1)
+	schedule_init = create_schedule(runtime_model)
+	schedule_run = read_root()
 
 
 	while (True):
 	while (True):
 		// If we are running, we just don't block for input and automatically do a step if there is no input
 		// If we are running, we just don't block for input and automatically do a step if there is no input
@@ -301,6 +384,8 @@ Void function execute_cbd(design_model : Element):
 				if (read_attribute(runtime_model, "time", "start_time") == read_attribute(runtime_model, "time", "current_time")):
 				if (read_attribute(runtime_model, "time", "start_time") == read_attribute(runtime_model, "time", "current_time")):
 					schedule = schedule_init
 					schedule = schedule_init
 				else:
 				else:
+					if (element_eq(schedule_run, read_root())):
+						schedule_run = create_schedule(runtime_model)
 					schedule = schedule_run
 					schedule = schedule_run
 				step_simulation(runtime_model, schedule)
 				step_simulation(runtime_model, schedule)
 			else:
 			else:
@@ -361,8 +446,10 @@ Void function execute_cbd(design_model : Element):
 				// Conforming, so do the retyping and sanitization step
 				// Conforming, so do the retyping and sanitization step
 				runtime_model = retype_to_runtime(design_model)
 				runtime_model = retype_to_runtime(design_model)
 				runtime_model = sanitize(runtime_model, old_runtime_model)
 				runtime_model = sanitize(runtime_model, old_runtime_model)
-				schedule_init = create_schedule(runtime_model, read_attribute(runtime_model, "time", "start_time"))
-				schedule_run = create_schedule(runtime_model, -1)
+				log("Create schedule")
+				schedule_init = create_schedule(runtime_model)
+				log("Remove schedule")
+				schedule_run = read_root()
 				old_runtime_model = runtime_model
 				old_runtime_model = runtime_model
 				output("CONFORMANCE_OK")
 				output("CONFORMANCE_OK")
 			else:
 			else: