include "primitives.alh" include "object_operations.alh" include "modelling.alh" Element function make_matching_schedule(LHS_model : Element): Element schedule Element workset Element all_elements Element full_all_elements Integer required_size String new_element Integer counter String next // Initialize schedule = create_node() workset = create_node() all_elements = allInstances(LHS_model, "Pre_Element") full_all_elements = set_copy(all_elements) required_size = read_nr_out(all_elements) // Need to keep adding to the schedule while (read_nr_out(schedule) < required_size): // 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]))): // Element is not usable, so pick another one new_element = set_pop(all_elements) set_add(workset, new_element) // Handle the workset while (read_nr_out(workset) > 0): // Still elements in the workset, so pop from these first next = set_pop(workset) // Check if element might not be already used somewhere if (bool_not(set_in(schedule, next))): if (set_in(full_all_elements, next)): list_append(schedule, next) // If it is an edge, we should also add the target and source if (is_edge(LHS_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]))) // Also add all outgoing links counter = read_nr_out(LHS_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))) return schedule! Element function get_possible_bindings(host_model : Element, LHS_model : Element, current_element : String, map : Element): Element options output("FIND BINDING") options = create_node() return 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 // Make the schedule first Element schedule schedule = make_matching_schedule(LHS_model) // Now follow the schedule, incrementally building all mappings Element mappings Element new_mappings Element new_map String current_element Element map String option Element options mappings = create_node() set_add(mappings, create_node()) while (bool_and(read_nr_out(schedule) > 0, read_nr_out(mappings) > 0)): current_element = list_pop(schedule, 0) log("Finding options for " + current_element) new_mappings = create_node() while (read_nr_out(mappings) > 0): map = set_pop(mappings) log("In context " + set_to_string(map)) options = get_possible_bindings(host_model, LHS_model, current_element, map) log("Found options " + set_to_string(options)) while (read_nr_out(options) > 0): option = set_pop(options) new_map = set_copy(map) dict_add(new_map, current_element, option) log(" --> adding mapping " + set_to_string(new_map)) set_add(new_mappings, new_map) mappings = new_mappings return mappings! Void function rewrite(host_model : Element, RHS_model : Element, mapping : Element): output("TODO: rewrite!") return! Void function transform(host_model : Element, LHS_model : Element, RHS_model : Element): Element mapping Element mappings // Get all possible mappings mappings = match(host_model, LHS_model) // Select one such mapping and rewrite it if (read_nr_out(mappings) > 0): // Mapping found, so can rewrite it mapping = set_pop(mappings) rewrite(host_model, RHS_model, mapping) else: output("No mapping found!") return!