123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- 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
- String src_label
- String dst_label
- String typename
- String original_typename
- log("FIND BINDING")
- options = create_node()
- typename = reverseKeyLookup(LHS_model["metamodel"]["model"], dict_read_node(LHS_model["type_mapping"], LHS_model["model"][current_element]))
- original_typename = string_substr(typename, 4, string_len(typename))
- log("Found type: " + typename)
- log("Original type: " + original_typename)
- if (is_edge(LHS_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")
- if (bool_and(set_in(dict_keys(map), src_label), set_in(dict_keys(map), dst_label))):
- // Source and destination are bound
- log("MERGE")
- options = allOutgoingAssociationInstances(host_model, map[src_label], original_typename)
- log("SRC: " + set_to_string(allOutgoingAssociationInstances(host_model, map[src_label], original_typename)))
- log("DST: " + set_to_string(allIncomingAssociationInstances(host_model, map[dst_label], original_typename)))
- options = set_overlap(options, allIncomingAssociationInstances(host_model, map[dst_label], original_typename))
- elif (set_in(dict_keys(map), src_label)):
- // Source is bound
- log("SOURCE")
- options = allOutgoingAssociationInstances(host_model, map[src_label], original_typename)
- elif (set_in(dict_keys(map), dst_label)):
- // Destination is bound
- log("DESTINATION")
- options = allIncomingAssociationInstances(host_model, map[dst_label], original_typename)
- else:
- // Neither is bound, so just get all of them
- log("ERROR: unbound source/target for association!")
- return create_node()!
- else:
- // Is a node, so check for already bound incoming/outgoing
- options = allInstances(host_model, original_typename)
- // Filter options further
- Element filtered_options
- String option
- filtered_options = create_node()
- log("Checking options")
- while (read_nr_out(options) > 0):
- option = set_pop(options)
- // Check for detecting same element twice
- log("Option: " + cast_v2s(option))
- if (bool_not(set_in(map, option))):
- // 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())):
- // No local constraints, so all is well
- log("No constraints, so ignore")
- set_add(filtered_options, option)
- else:
- log("Verify constraints first")
- // Check local constraints and add only if positive
- Element constraint_function
- constraint_function = read_attribute(LHS_model, current_element, "constraint")
- Boolean result
- result = constraint_function(host_model, option)
- if (result):
- set_add(filtered_options, option)
- else:
- log("ERROR: already matched")
- 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
- // 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 " + cast_v2s(read_attribute(LHS_model, current_element, "label")))
- new_mappings = create_node()
- while (read_nr_out(mappings) > 0):
- map = set_pop(mappings)
- log("In context " + dict_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 = dict_copy(map)
- dict_add(new_map, read_attribute(LHS_model, current_element, "label"), option)
- log(" --> adding mapping " + dict_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)
- log("Found total mappings: " + cast_v2s(read_nr_out(mappings)))
- // Select one such mapping and rewrite it
- if (read_nr_out(mappings) > 0):
- // Mapping found, so can rewrite it
- mapping = set_pop(mappings)
- log("Found example mapping " + dict_to_string(mapping))
- rewrite(host_model, RHS_model, mapping)
- else:
- output("No mapping found!")
- return!
|