Bläddra i källkod

Fix reachability graph construction and printing

Yentl Van Tendeloo 8 år sedan
förälder
incheckning
320ffd3b32

+ 16 - 0
bootstrap/primitives.alc

@@ -292,6 +292,22 @@ Boolean function set_equality(sa : Element, sb : Element):
 	
 	return True!
 
+Boolean function dict_eq(da : Element, db : Element):
+	if (bool_not(set_equality(dict_keys(da), dict_keys(db)))):
+		// They don't even share the same keys
+		return False!
+
+	Element keys
+	Element key
+	keys = dict_keys(da)
+	while (read_nr_out(keys) > 0):
+		key = set_pop(keys)
+		if (value_neq(da[key], db[key])):
+			// Value that is not equal
+			return False!
+
+	return True!
+
 Element function dict_copy(d : Element):
 	String result
 	Element keys

+ 0 - 80
core/core_algorithm.alc

@@ -131,7 +131,6 @@ Void function main():
 	instantiate_link(core, "owner", "", al_model, admin_user)
 
 	// Add the Manual Operation formalism
-	log("Adding manual model")
 	Element manual
 	String manual_model
 	manual = instantiate_model(scd)
@@ -142,7 +141,6 @@ Void function main():
 	instantiate_attribute(core, manual_model, "permissions", "221")
 	instance_of = instantiate_link(core, "instanceOf", "", manual_model, scd_model)
 	instantiate_attribute(core, instance_of, "type_mapping", create_node())
-	log("Added manual model")
 
 	// Make necessary links for the formalism to the owners
 	instantiate_link(core, "group", "", manual_model, admin_group)
@@ -492,28 +490,20 @@ Boolean function enact_action(pm : Element, element : String, prefix : String, u
 	lst = allAssociationOrigins(pm, element, "Consumes")
 	while (read_nr_out(lst) > 0):
 		elem = set_pop(lst)
-		log("Origin: " + elem)
 		// As there are no inheritance relations between full models, we can just read out the typename
 		type_name = read_attribute(pm, elem, "type")
 		dict_add(inputs, type_name, string_join(prefix, read_attribute(pm, elem, "name")))
-	log("Inputs: " + dict_to_string(inputs))
 
 	// Find all outputs and their types (i.e., key)
-	log("Read all producers of " + element)
 	lst = allAssociationDestinations(pm, element, "Produces")
 	while (read_nr_out(lst) > 0):
 		elem = set_pop(lst)
-		log("Destination: " + elem)
 		// As there are no inheritance relations between full models, we can just read out the typename
 		type_name = read_attribute(pm, elem, "type")
-		log("Type name: " + type_name)
 		dict_add(outputs, type_name, string_join(prefix, read_attribute(pm, elem, "name")))
 		dict_add(output_mms, type_name, get_full_model(get_model_id(type_name)))
-	log("Outputs: " + dict_to_string(outputs))
 
 	exact_type = read_type(core, transformation_id)
-	log("Exact type: " + exact_type)
-	log("EXECUTE OPERATION " + cast_e2s(read_attribute(core, transformation_id, "name")))
 	if (exact_type == "ModelTransformation"):
 		// Model transformation is always in-place and uses only a single metamodel
 		// Therefore, we must:
@@ -534,20 +524,15 @@ Boolean function enact_action(pm : Element, element : String, prefix : String, u
 		// 1) Create empty instance of merged metamodel
 
 		ramified_metamodel_id = set_pop(followAssociation(core, transformation_id, "instanceOf"))
-		log("Got ramified: " + ramified_metamodel_id)
 		trace_links = allOutgoingAssociationInstances(core, ramified_metamodel_id, "tracability")
-		log("Trace links resolved")
 		merged_metamodel_id = ""
 		while (read_nr_out(trace_links) > 0):
 			trace_link_id = set_pop(trace_links)
 			if (value_eq(read_attribute(core, trace_link_id, "type"), "RAMified")):
 				merged_metamodel_id = readAssociationDestination(core, trace_link_id)
-				log("Got merged metamodel: " + merged_metamodel_id)
 
 		if (merged_metamodel_id != ""):
-			log("Ready for instantiate")
 			merged_model = instantiate_model(get_full_model(merged_metamodel_id))
-			log("Instantiated model")
 
 			// 2) Merge source models
 
@@ -556,9 +541,7 @@ Boolean function enact_action(pm : Element, element : String, prefix : String, u
 			Element input_keys
 			Element output_keys
 
-			log("Fetching input keys")
 			input_keys = dict_keys(inputs)
-			log("Input keys: " + set_to_string(input_keys))
 			while (read_nr_out(input_keys) > 0):
 				key = set_pop(input_keys)
 				model_join(merged_model, get_full_model(get_model_id(inputs[key])), key + "/")
@@ -597,36 +580,24 @@ Boolean function enact_action(pm : Element, element : String, prefix : String, u
 		String key
 		Element func
 
-		log("Action Language execution starts!")
-		log("Getting full model for transformation")
-		log("Got model: " + cast_e2s(read_attribute(core, transformation_id, "location")))
-
 		// 1) Group source models in dictionary
 		//  --> This is just the "inputs" variable, but resolve all references
-		log("Create inputs")
 		new_inputs = create_node()
 		input_keys = dict_keys(inputs)
 		while (read_nr_out(input_keys) > 0):
 			key = set_pop(input_keys)
-			log("Resolving " + cast_e2s(key))
-			log("  --> " + cast_e2s(inputs[key]))
-			log("  ID " + cast_e2s(get_model_id(inputs[key])))
-			log("  full m " + cast_e2s(get_full_model(get_model_id(inputs[key]))))
 			dict_add(new_inputs, key, get_full_model(get_model_id(inputs[key])))
 		inputs = new_inputs
 
 		// 2) Execute action language model
 		func = get_func_AL_model(get_full_model(transformation_id))
-		log("Ready to execute: " + cast_e2s(func))
 
 		result = func(inputs, output_mms)
-		log("Result: " + cast_e2s(result))
 
 		// 3) Split output dictionary back to seperate models
 		output_keys = dict_keys(outputs)
 		while (read_nr_out(output_keys) > 0):
 			key = set_pop(output_keys)
-			log("Splitting " + key)
 
 			// Check if the destination model already exists
 			if (get_model_id(outputs[key]) == ""):
@@ -636,10 +607,7 @@ Boolean function enact_action(pm : Element, element : String, prefix : String, u
 				// Model exists, so we overwrite
 				model_overwrite(result[key], get_model_id(outputs[key]))
 
-		log("Finished")
-
 	elif (exact_type == "ManualOperation"):
-		log("Manual operation starts!")
 		// Identical to model transformations, but give control to users for modification
 		// 1) Create empty instance of merged metamodel
 		Element input_model
@@ -671,9 +639,7 @@ Boolean function enact_action(pm : Element, element : String, prefix : String, u
 
 			// 3) Transform
 
-			log("Start modify")
 			modify(merged_model, True)
-			log("Modify finished")
 
 			// 4) Split in different files depending on type
 
@@ -687,7 +653,6 @@ Boolean function enact_action(pm : Element, element : String, prefix : String, u
 				split_off_model = model_split(merged_model, get_full_model(desired_metamodel_id), key + "/")
 
 				// Check if the destination model already exists
-				log("Writing output to " + cast_v2s(outputs[key]))
 				if (get_model_id(outputs[key]) == ""):
 					// New model
 					model_create(split_off_model, outputs[key], user_id, desired_metamodel_id, "Model")
@@ -700,8 +665,6 @@ Boolean function enact_action(pm : Element, element : String, prefix : String, u
 		// TODO find out whether it succeeded or not
 		result = True
 	else:
-		log("Type name: " + exact_type)
-		log("From " + transformation_id)
 		output("Did not know how to interpret model of type " + exact_type)
 
 	return result!
@@ -731,7 +694,6 @@ Void function enact_PM(pm : Element, prefix : String, user_id : String):
 		tuple = set_pop(worklist)
 		element = tuple[0]
 		result = tuple[1]
-		log("EXECUTING " + element)
 
 		// Find the type (to see what to do with it)
 		//   this does not yet yield the type of transformation, if it is an Execution
@@ -772,8 +734,6 @@ Void function enact_PM(pm : Element, prefix : String, user_id : String):
 			// This the difficult part!
 
 			result = enact_action(pm, element, prefix, user_id)
-			log("Executed Exec of " + element)
-			log("Result: " + cast_v2s(result))
 
 		elif (type == "Decision"):
 			// If the previous result is true, we add the normal one, otherwise the false one
@@ -789,7 +749,6 @@ Void function enact_PM(pm : Element, prefix : String, user_id : String):
 		String next
 		while (read_nr_out(all_next) > 0):
 			next = set_pop(all_next)
-			log("Queueing next: " + next)
 			set_add(worklist, create_tuple(next, result))
 
 	// Reached a finish element, so stop
@@ -887,7 +846,6 @@ Void function user_function_skip_init(user_id : String):
 			String process_id
 
 			output("Which process model do you want to execute?")
-			log("Execute process!")
 			process_id = get_model_id(input())
 			if (process_id != ""):
 				if (allow_read(user_id, process_id)):
@@ -1010,7 +968,6 @@ Void function user_function_skip_init(user_id : String):
 
 								// 3) Transform
 
-								log("EXECUTE TRANSFORMATION " + cast_e2s(read_attribute(core, transformation_id, "name")))
 								result = transform(merged_model, schedule_model)
 								output("Transformation executed with result: " + cast_v2s(result))
 
@@ -1044,35 +1001,23 @@ Void function user_function_skip_init(user_id : String):
 							String key
 							Element func
 
-							log("Action Language execution starts!")
-							log("Getting full model for transformation")
-							log("Got model: " + cast_e2s(read_attribute(core, transformation_id, "location")))
-
 							// 1) Group source models in dictionary
 							//  --> This is just the "inputs" variable, but resolve all references
-							log("Create inputs")
 							new_inputs = create_node()
 							input_keys = dict_keys(inputs)
 							while (read_nr_out(input_keys) > 0):
 								key = set_pop(input_keys)
-								log("Resolving " + cast_e2s(key))
-								log("  --> " + cast_e2s(inputs[key]))
-								log("  ID " + cast_e2s(get_model_id(inputs[key])))
-								log("  full m " + cast_e2s(get_full_model(get_model_id(inputs[key]))))
 								dict_add(new_inputs, key, get_full_model(get_model_id(inputs[key])))
 							inputs = new_inputs
 
 							// 2) Execute action language model
 							func = get_func_AL_model(get_full_model(transformation_id))
-							log("Ready to execute: " + cast_e2s(func))
 							result = func(inputs)
-							log("Result: " + cast_e2s(result))
 
 							// 3) Split output dictionary back to seperate models
 							output_keys = dict_keys(outputs)
 							while (read_nr_out(output_keys) > 0):
 								key = set_pop(output_keys)
-								log("Splitting " + key)
 
 								// Check if the destination model already exists
 								if (get_model_id(outputs[key]) == ""):
@@ -1082,10 +1027,7 @@ Void function user_function_skip_init(user_id : String):
 									// Model exists, so we overwrite
 									model_overwrite(result[key], get_model_id(outputs[key]))
 
-							log("Finished")
-
 						elif (exact_type == "ManualOperation"):
-							log("Manual operation starts!")
 							// Identical to model transformations, but give control to users for modification
 							// 1) Create empty instance of merged metamodel
 							Element input_model
@@ -1117,9 +1059,7 @@ Void function user_function_skip_init(user_id : String):
 
 								// 3) Transform
 
-								log("Start modify")
 								modify(merged_model, True)
-								log("Modify finished")
 
 								// 4) Split in different files depending on type
 
@@ -1265,7 +1205,6 @@ Void function user_function_skip_init(user_id : String):
 			String new_model_id
 
 			old_type_id = ""
-			log("Adding MT language")
 
 			// Read involved formalisms
 			all_formalisms = create_node()
@@ -1300,9 +1239,7 @@ Void function user_function_skip_init(user_id : String):
 					String tracability_link
 
 					// New location is available, so write
-					log("FUSE")
 					merged_formalism = model_fuse(set_copy(all_formalisms))
-					log("Fuse OK")
 					model_create(merged_formalism, "__merged_" + name, user_id, type_id, "Model")
 					merged_formalism_id = get_model_id("__merged_" + name)
 
@@ -1313,9 +1250,7 @@ Void function user_function_skip_init(user_id : String):
 						instantiate_attribute(core, tracability_link, "type", "merged")
 
 					// Merge complete, now RAMify!
-					log("RAM")
 					ramified_formalism = ramify(merged_formalism)
-					log("RAMed")
 					model_create(ramified_formalism, name, user_id, type_id, "Model")
 					ramified_formalism_id = get_model_id(name)
 
@@ -1446,9 +1381,7 @@ Void function user_function_skip_init(user_id : String):
 
 				// Write out a merged metamodel containing all these models: this is the MM for the manual operation
 				// New location is available, so write
-				log("FUSE")
 				merged_formalism = model_fuse(set_copy(all_formalisms))
-				log("Fuse OK")
 				model_create(merged_formalism, "__merged_" + name, user_id, type_id, "Model")
 				merged_formalism_id = get_model_id("__merged_" + name)
 
@@ -1465,17 +1398,13 @@ Void function user_function_skip_init(user_id : String):
 				String link
 				String dst
 
-				log("Adding inputs")
 				while (read_nr_out(source) > 0):
 					dst = set_pop(source)
-					log(" for " + dst)
 					link = instantiate_link(core, "transformInput", "", model_id, dst)
 					instantiate_attribute(core, link, "name", read_attribute(core, dst, "name"))
 
-				log("Adding outputs")
 				while (read_nr_out(target) > 0):
 					dst = set_pop(target)
-					log(" for " + dst)
 					link = instantiate_link(core, "transformOutput", "", model_id, dst)
 					instantiate_attribute(core, link, "name", read_attribute(core, dst, "name"))
 			else:
@@ -1525,15 +1454,10 @@ Void function user_function_skip_init(user_id : String):
 			output("Name of Action Language model?")
 			name = input()
 
-			log("Add AL is fine!")
 			if (get_model_id(name) == ""):
 				// Finished with all information, now create the model itself!
 				output("Waiting for model constructors...")
-				log("AL model: " + cast_e2s(get_model_id("ActionLanguage")))
-				log("Location: " + cast_e2s(read_attribute(core, get_model_id("ActionLanguage"), "location")))
-				log("Imported: " + cast_e2s(import_node(read_attribute(core, get_model_id("ActionLanguage"), "location"))))
 				add_code_model(get_full_model(get_model_id("ActionLanguage")), "AL/" + name, construct_function())
-				log("Exported to " + cast_e2s(import_node("AL/" + name)))
 				model_create(import_node("AL/" + name), name, user_id, get_model_id("ActionLanguage"), "ActionLanguage")
 				model_id = get_model_id(name)
 
@@ -1541,17 +1465,13 @@ Void function user_function_skip_init(user_id : String):
 				String link
 				String dst
 
-				log("Adding inputs")
 				while (read_nr_out(source) > 0):
 					dst = set_pop(source)
-					log(" for " + dst)
 					link = instantiate_link(core, "transformInput", "", model_id, dst)
 					instantiate_attribute(core, link, "name", read_attribute(core, dst, "name"))
 
-				log("Adding outputs")
 				while (read_nr_out(target) > 0):
 					dst = set_pop(target)
-					log(" for " + dst)
 					link = instantiate_link(core, "transformOutput", "", model_id, dst)
 					instantiate_attribute(core, link, "name", read_attribute(core, dst, "name"))
 			else:

+ 57 - 20
integration/code/reachability.alc

@@ -18,6 +18,7 @@ Element function reachability_graph(params : Element, output_mms : Element):
 	Element reachable_states
 	Element keys
 	String transition
+	String new_transition
 	String state
 	String name
 	String link
@@ -35,29 +36,22 @@ Element function reachability_graph(params : Element, output_mms : Element):
 	result = create_node()
 	out_model = instantiate_model(output_mms["ReachabilityGraph"])
 	in_model = params["PetriNet"]
-	log("Got in_model: " + cast_e2s(in_model))
-	log("Params: " + dict_to_string(params))
-	log("Params: " + cast_e2s(in_model))
-	log("Keys in type: " + set_to_string(dict_keys(in_model["metamodel"]["model"])))
 
 	// Create a dictionary representation for each transition
 	transition_vectors_produce = create_node()
 	transition_vectors_consume = create_node()
 	all_transitions = allInstances(in_model, "Transition")
-	log("Got all transitions: " + set_to_string(all_transitions))
 	while (read_nr_out(all_transitions) > 0):
 		transition = set_pop(all_transitions)
 
 		tv = create_node()
 		links = allIncomingAssociationInstances(in_model, transition, "P2T")
-		log("All links: " + set_to_string(links))
 		while (read_nr_out(links) > 0):
 			link = set_pop(links)
 			name = reverseKeyLookup(in_model["model"], read_edge_src(in_model["model"][link]))
 			link_weight = read_attribute(in_model, link, "weight")
 			dict_add(tv, name, link_weight)
 		dict_add(transition_vectors_consume, transition, tv)
-		log("Consume OK: " + dict_to_string(transition_vectors_consume[transition]))
 
 		tv = create_node()
 		links = allOutgoingAssociationInstances(in_model, transition, "T2P")
@@ -67,19 +61,15 @@ Element function reachability_graph(params : Element, output_mms : Element):
 			link_weight = read_attribute(in_model, link, "weight")
 			dict_add(tv, name, link_weight)
 		dict_add(transition_vectors_produce, transition, tv)
-		log("Produce OK: " + dict_to_string(transition_vectors_produce[transition]))
 
-	log("Ready for work!")
 	workset = create_node()
 
 	all_places = allInstances(in_model, "Place")
-	log("All places: " + set_to_string(all_places))
 	dict_repr = create_node()
 	while (read_nr_out(all_places) > 0):
 		place = set_pop(all_places)
 		dict_add(dict_repr, place, read_attribute(in_model, place, "tokens"))
 
-	log("Representation of first state: " + dict_to_string(dict_repr))
 	all_transitions_original = allInstances(in_model, "Transition")
 
 	mappings = create_node()
@@ -90,6 +80,17 @@ Element function reachability_graph(params : Element, output_mms : Element):
 	dict_add(mappings, state_id, create_node())
 	set_add(workset, state_id)
 
+	// And add in the model itself
+	state = instantiate_node(out_model, "State", cast_i2s(state_id))
+	instantiate_attribute(out_model, state, "name", cast_i2s(state_id))
+	keys = dict_keys(dict_repr)
+	while (read_nr_out(keys) > 0):
+		key = set_pop(keys)
+		place = instantiate_node(out_model, "Place", "")
+		instantiate_attribute(out_model, place, "name", read_attribute(in_model, key, "name"))
+		instantiate_attribute(out_model, place, "tokens", dict_repr[key])
+		instantiate_link(out_model, "Contains", "", state, place)
+
 	while (read_nr_out(workset) > 0):
 		state_id = set_pop(workset)
 
@@ -101,7 +102,6 @@ Element function reachability_graph(params : Element, output_mms : Element):
 		all_transitions = set_copy(all_transitions_original)
 		while (read_nr_out(all_transitions) > 0):
 			transition = set_pop(all_transitions)
-			log("Compute if possible for " + transition)
 			keys = dict_keys(transition_vectors_consume[transition])
 			possible = True
 			while (read_nr_out(keys) > 0):
@@ -116,23 +116,60 @@ Element function reachability_graph(params : Element, output_mms : Element):
 			if (possible):
 				dict_repr = dict_copy(dict_repr)
 				// Transition can execute, so compute and add the new state based on the consume/produce vectors
+				log("Before transition: " + dict_to_string(dict_repr))
 				keys = dict_keys(transition_vectors_consume[transition])
-				log("Deduct")
 				while (read_nr_out(keys) > 0):
 					key = set_pop(keys)
 					dict_overwrite(dict_repr, key, integer_subtraction(dict_repr[key], transition_vectors_consume[transition][key]))
+
 				keys = dict_keys(transition_vectors_produce[transition])
-				log("Increment")
 				while (read_nr_out(keys) > 0):
 					key = set_pop(keys)
 					dict_overwrite(dict_repr, key, integer_addition(dict_repr[key], transition_vectors_produce[transition][key]))
+				log("After transition: " + dict_to_string(dict_repr))
 
-				// Add the target to workset, as it is new
-				dict_add(reachable_states, next_id, dict_repr)
-				dict_add(mappings, next_id, create_node())
-				dict_add(mappings[state_id], transition, next_id)
-				set_add(workset, next_id)
-				next_id = next_id + 1
+				// Check if this state already has an associated ID
+				Integer other_state_id
+				Integer target_id
+
+				keys = dict_keys(reachable_states)
+				target_id = -1
+				while (read_nr_out(keys) > 0):
+					other_state_id = set_pop(keys)
+
+					if (dict_eq(reachable_states[other_state_id], dict_repr)):
+						target_id = other_state_id
+						break!
+
+				if (target_id == -1):
+					// New state
+					target_id = next_id
+					next_id = next_id + 1
+
+					// Add to all data structures
+					dict_add(reachable_states, target_id, dict_repr)
+					dict_add(mappings, target_id, create_node())
+					set_add(workset, target_id)
+
+					// And add in the model itself
+					state = instantiate_node(out_model, "State", cast_i2s(target_id))
+					instantiate_attribute(out_model, state, "name", cast_i2s(target_id))
+
+					keys = dict_keys(dict_repr)
+					while (read_nr_out(keys) > 0):
+						key = set_pop(keys)
+						place = instantiate_node(out_model, "Place", "")
+						instantiate_attribute(out_model, place, "name", read_attribute(in_model, key, "name"))
+						instantiate_attribute(out_model, place, "tokens", dict_repr[key])
+						instantiate_link(out_model, "Contains", "", state, place)
+
+				// Anyway, we have found a transition, which we should store
+				dict_add(mappings[state_id], transition, target_id)
+
+				// And also store it in the model itself
+				new_transition = instantiate_link(out_model, "Transition", "", cast_i2s(state_id), cast_i2s(target_id))
+				instantiate_attribute(out_model, new_transition, "name", read_attribute(in_model, transition, "name"))
+				log("Add transition name: " + cast_v2s(read_attribute(in_model, transition, "name")))
 
 	dict_add(result, "ReachabilityGraph", out_model)
 	return result!

+ 3 - 1
integration/code/reachability_graph.mvc

@@ -6,7 +6,9 @@ SimpleClassDiagrams ReachabilityGraph {
     SimpleAttribute String {}
     SimpleAttribute Natural {}
 
-    Class State {}
+    Class State {
+        name : String
+    }
     Class Place {
         name : String
         tokens : Natural

+ 6 - 2
integration/code/reachabilitygraph_print.mvc

@@ -20,12 +20,14 @@ ReachabilityGraph_RAM reachabilitygraph_print {
                             log("State action")
                             Element dict_values
                             Element all_values
+                            String place
                             dict_values = create_node()
-                            all_values = allAssociationDestinations(model, name, "Contains")
+                            all_values = allAssociationDestinations(model, name, "ReachabilityGraph/Contains")
+                            log("All values: " + set_to_string(all_values))
                             while (read_nr_out(all_values) > 0):
-                                String place
                                 place = set_pop(all_values)
                                 dict_add(dict_values, read_attribute(model, place, "name"), read_attribute(model, place, "tokens"))
+                            log((cast_v2s(mapping["0"]) + ": ") + dict_to_string(dict_values))
                             output((cast_v2s(mapping["0"]) + ": ") + dict_to_string(dict_values))
                             return!
                         $
@@ -57,6 +59,7 @@ ReachabilityGraph_RAM reachabilitygraph_print {
                     action = $
                         Void function action(model : Element, name : String, mapping : Element):
                             log("Transition action")
+                            log((((cast_v2s(mapping["0"]) + " --[") + cast_v2s(read_attribute(model, name, "name"))) + "]--> ") + cast_v2s(mapping["1"]))
                             output((((cast_v2s(mapping["0"]) + " --[") + cast_v2s(read_attribute(model, name, "name"))) + "]--> ") + cast_v2s(mapping["1"]))
                             return!
                         $
@@ -65,6 +68,7 @@ ReachabilityGraph_RAM reachabilitygraph_print {
         }
     }
 
+    Initial (schedule, print_states) {}
     OnSuccess (print_states, print_transitions) {}
     OnFailure (print_states, failure) {}
     OnSuccess (print_transitions, success) {}

+ 4 - 0
integration/test_mvc.py

@@ -1949,6 +1949,10 @@ class TestModelverseCore(unittest.TestCase):
                     "instantiate",
                         "PetriNet/Transition",
                         "t1",
+                    "attr_add",
+                        "t1",
+                        "name",
+                        "t1",
                     "instantiate",
                         "PetriNet/P2T",
                         "p2t",

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

@@ -103,6 +103,7 @@ String function list_to_string(set : Element)
 String function dict_to_string(dict : Element)
 Element function set_overlap(sa : Element, sb : Element)
 Element function set_equality(sa : Element, sb : Element)
+Element function dict_eq(da : Element, db : Element)
 Element function dict_copy(dict : Element)
 Element function set_to_list(s : Element)
 Element function create_tuple(a : Element, b : Element)