transform.alc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. include "primitives.alh"
  2. include "object_operations.alh"
  3. include "modelling.alh"
  4. Element function make_matching_schedule(LHS_model : Element):
  5. Element schedule
  6. Element workset
  7. Element all_elements
  8. Element full_all_elements
  9. Integer required_size
  10. String new_element
  11. Integer counter
  12. String next
  13. // Initialize
  14. schedule = create_node()
  15. workset = create_node()
  16. all_elements = allInstances(LHS_model, "Pre_Element")
  17. full_all_elements = set_copy(all_elements)
  18. required_size = read_nr_out(all_elements)
  19. // Need to keep adding to the schedule
  20. while (read_nr_out(schedule) < required_size):
  21. // workset is empty, but we still need to add to the list
  22. // Therefore, we pick a random, unbound node, and add it to the workset
  23. new_element = set_pop(all_elements)
  24. while (bool_or(set_in(schedule, new_element), is_edge(LHS_model["model"][new_element]))):
  25. // Element is not usable, so pick another one
  26. new_element = set_pop(all_elements)
  27. set_add(workset, new_element)
  28. // Handle the workset
  29. while (read_nr_out(workset) > 0):
  30. // Still elements in the workset, so pop from these first
  31. next = set_pop(workset)
  32. // Check if element might not be already used somewhere
  33. if (bool_not(set_in(schedule, next))):
  34. if (set_in(full_all_elements, next)):
  35. list_append(schedule, next)
  36. // If it is an edge, we should also add the target and source
  37. if (is_edge(LHS_model["model"][next])):
  38. // Add the target/source to the schedule
  39. set_add(workset, reverseKeyLookup(LHS_model["model"], read_edge_src(LHS_model["model"][next])))
  40. set_add(workset, reverseKeyLookup(LHS_model["model"], read_edge_dst(LHS_model["model"][next])))
  41. // Also add all outgoing links
  42. counter = read_nr_out(LHS_model["model"][next])
  43. while (counter > 0):
  44. counter = counter - 1
  45. if (set_in_node(LHS_model["model"], read_out(LHS_model["model"][next], counter))):
  46. set_add(workset, reverseKeyLookup(LHS_model["model"], read_out(LHS_model["model"][next], counter)))
  47. return schedule!
  48. Element function get_possible_bindings(host_model : Element, LHS_model : Element, current_element : String, map : Element):
  49. Element options
  50. String src_label
  51. String dst_label
  52. String typename
  53. String original_typename
  54. log("FIND BINDING")
  55. options = create_node()
  56. typename = reverseKeyLookup(LHS_model["metamodel"]["model"], dict_read_node(LHS_model["type_mapping"], LHS_model["model"][current_element]))
  57. original_typename = string_substr(typename, 4, string_len(typename))
  58. log("Found type: " + typename)
  59. log("Original type: " + original_typename)
  60. if (is_edge(LHS_model["model"][current_element])):
  61. // Is an edge, so check for already bound source/target
  62. src_label = read_attribute(LHS_model, reverseKeyLookup(LHS_model["model"], read_edge_src(LHS_model["model"][current_element])), "label")
  63. dst_label = read_attribute(LHS_model, reverseKeyLookup(LHS_model["model"], read_edge_dst(LHS_model["model"][current_element])), "label")
  64. if (bool_and(set_in(dict_keys(map), src_label), set_in(dict_keys(map), dst_label))):
  65. // Source and destination are bound
  66. log("MERGE")
  67. options = allOutgoingAssociationInstances(host_model, map[src_label], original_typename)
  68. log("SRC: " + set_to_string(allOutgoingAssociationInstances(host_model, map[src_label], original_typename)))
  69. log("DST: " + set_to_string(allIncomingAssociationInstances(host_model, map[dst_label], original_typename)))
  70. options = set_overlap(options, allIncomingAssociationInstances(host_model, map[dst_label], original_typename))
  71. elif (set_in(dict_keys(map), src_label)):
  72. // Source is bound
  73. log("SOURCE")
  74. options = allOutgoingAssociationInstances(host_model, map[src_label], original_typename)
  75. elif (set_in(dict_keys(map), dst_label)):
  76. // Destination is bound
  77. log("DESTINATION")
  78. options = allIncomingAssociationInstances(host_model, map[dst_label], original_typename)
  79. else:
  80. // Neither is bound, so just get all of them
  81. log("ERROR: unbound source/target for association!")
  82. return create_node()!
  83. else:
  84. // Is a node, so check for already bound incoming/outgoing
  85. options = allInstances(host_model, original_typename)
  86. // Filter options further
  87. Element filtered_options
  88. String option
  89. filtered_options = create_node()
  90. log("Checking options")
  91. while (read_nr_out(options) > 0):
  92. option = set_pop(options)
  93. // Check for detecting same element twice
  94. log("Option: " + cast_v2s(option))
  95. if (bool_not(set_in(map, option))):
  96. // Option is already present with another label, so skip this!
  97. // Check for local constraints of element
  98. if (element_eq(read_attribute(LHS_model, current_element, "constraint"), read_root())):
  99. // No local constraints, so all is well
  100. log("No constraints, so ignore")
  101. set_add(filtered_options, option)
  102. else:
  103. log("Verify constraints first")
  104. // Check local constraints and add only if positive
  105. Element constraint_function
  106. constraint_function = read_attribute(LHS_model, current_element, "constraint")
  107. Boolean result
  108. result = constraint_function(host_model, option)
  109. if (result):
  110. set_add(filtered_options, option)
  111. else:
  112. log("ERROR: already matched")
  113. return filtered_options!
  114. Element function match(host_model : Element, LHS_model : Element):
  115. // Match the LHS_model to the host_model, returning all possible mappings from LHS_model elements to host_model elements
  116. // Make the schedule first
  117. Element schedule
  118. schedule = make_matching_schedule(LHS_model)
  119. // Now follow the schedule, incrementally building all mappings
  120. Element mappings
  121. Element new_mappings
  122. Element new_map
  123. String current_element
  124. Element map
  125. String option
  126. Element options
  127. mappings = create_node()
  128. set_add(mappings, create_node())
  129. while (bool_and(read_nr_out(schedule) > 0, read_nr_out(mappings) > 0)):
  130. current_element = list_pop(schedule, 0)
  131. log("Finding options for " + cast_v2s(read_attribute(LHS_model, current_element, "label")))
  132. new_mappings = create_node()
  133. while (read_nr_out(mappings) > 0):
  134. map = set_pop(mappings)
  135. log("In context " + dict_to_string(map))
  136. options = get_possible_bindings(host_model, LHS_model, current_element, map)
  137. log("Found options " + set_to_string(options))
  138. while (read_nr_out(options) > 0):
  139. option = set_pop(options)
  140. new_map = dict_copy(map)
  141. dict_add(new_map, read_attribute(LHS_model, current_element, "label"), option)
  142. log(" --> adding mapping " + dict_to_string(new_map))
  143. set_add(new_mappings, new_map)
  144. mappings = new_mappings
  145. return mappings!
  146. Void function rewrite(host_model : Element, RHS_model : Element, mapping : Element):
  147. output("TODO: rewrite!")
  148. return!
  149. Void function transform(host_model : Element, LHS_model : Element, RHS_model : Element):
  150. Element mapping
  151. Element mappings
  152. // Get all possible mappings
  153. mappings = match(host_model, LHS_model)
  154. log("Found total mappings: " + cast_v2s(read_nr_out(mappings)))
  155. // Select one such mapping and rewrite it
  156. if (read_nr_out(mappings) > 0):
  157. // Mapping found, so can rewrite it
  158. mapping = set_pop(mappings)
  159. log("Found example mapping " + dict_to_string(mapping))
  160. rewrite(host_model, RHS_model, mapping)
  161. else:
  162. output("No mapping found!")
  163. return!