environment_to_EPN.alc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Pseudo-code
  2. // TODO: add link to the ports of the boundary
  3. // TODO: update MM to reflect the new changes to the structure (everything is an Activity with a Next link, and everything has a duration)
  4. // init_place = new_place()
  5. // branches = [(init_place, [(0, topmost_model)]]
  6. // while branches:
  7. // prev, options = branches.pop()
  8. // nr = find_min_time(options)
  9. // time, cur = options.pop(nr)
  10. //
  11. // if type(cur) == "Event":
  12. // // Just add the current node and augment the duration for the next one
  13. // prev_model = new_element(cur)
  14. // if (cur.next != None):
  15. // options.append((time + cur.next.duration, cur.next))
  16. // branches.append((prev_model, options))
  17. // else:
  18. // // recurse upwards until we can follow a link
  19. // elem = containee(cur)
  20. // while elem.next_activity == None and containee(elem) != None:
  21. // elem = containee(elem)
  22. // if containee(elem) == None:
  23. // // finished this branch
  24. // continue!
  25. // else:
  26. // cur = elem.next_activity
  27. // options.append((time + elem.duration, cur.next))
  28. // branches.append((prev_model, options))
  29. // elif type(cur) == "Sequence":
  30. // options.append((time + first.duration, cur.first))
  31. // branches.append((prev_model, options))
  32. // elif type(cur) == "Parallel":
  33. // // Add all starts of the parallel as potential next one
  34. // // But keep the previous source, as we only expanded
  35. // for next in cur.start_nodes:
  36. // options.append((time + next.duration, next))
  37. // branches.append((prev, options))
  38. // elif type(cur) == "Alternative":
  39. // // Expand into new branches, but keep the options as is (add the individual options though)
  40. // for next in cur.start_nodes:
  41. // options.append((time + next.duration, next))
  42. // // Don't rewrite the source, as we effectively want to branch out from this node
  43. // branches.append(prev, options)
  44. include "primitives.alh"
  45. include "modelling.alh"
  46. include "object_operations.alh"
  47. Element function env_to_EPN(params : Element, output_mms : Element):
  48. Element result
  49. Element out_model
  50. Element in_model
  51. String init_place
  52. String current_activity
  53. Element branches
  54. Element options
  55. Element branch
  56. String previous_place
  57. Integer i
  58. Integer cnt
  59. Integer min_time
  60. Integer index_min_time
  61. Element option
  62. Integer current_time
  63. String new_transition
  64. String new_model
  65. Element containers
  66. Element new_options
  67. Element inner_elements
  68. Element entry
  69. String type
  70. String prev_model
  71. String element
  72. result = create_node()
  73. out_model = instantiate_model(output_mms["Encapsulated_PetriNet"])
  74. in_model = params["environment"]
  75. // Create the initial place
  76. init_place = instantiate_node(out_model, "Place", "")
  77. instantiate_attribute(out_model, init_place, "tokens", 1)
  78. // Set current element to the TopActivity, which will be expanded
  79. current_activity = set_pop(allInstances(in_model, "TopActivity"))
  80. // Initialize the data structure with the current element and initial place
  81. branches = create_node()
  82. options = create_node()
  83. list_append(options, create_tuple(0, current_activity))
  84. set_add(branches, create_tuple(init_place, options))
  85. // Keep going as long as there are branches to resolve
  86. while (read_nr_out(branches) > 0):
  87. // Still a branch, so pick one at random
  88. branch = set_pop(branches)
  89. previous_place = branch[0]
  90. options = branch[1]
  91. // Find the index of the option with the lowest time (first element of tuple)
  92. i = 0
  93. cnt = list_len(options)
  94. min_time = 9999999
  95. index_min_time = -1
  96. while (i < cnt):
  97. entry = list_read(options, i)
  98. if (integer_lt(entry[0], min_time)):
  99. min_time = entry[0]
  100. index_min_time = i
  101. i = i + 1
  102. // Pop the minimal option
  103. option = list_pop(options, index_min_time)
  104. current_time = option[0]
  105. current_activity = option[1]
  106. // Figure out the type
  107. type = read_type(in_model, current_activity)
  108. // Now branch based on the type
  109. if (type == "Event"):
  110. // Process an event: update the PN and go to the next activity
  111. new_transition = instantiate_node(out_model, "Transition", "")
  112. new_model = instantiate_node(out_model, "Place", "")
  113. instantiate_link(out_model, "P2T", "", prev_model, new_transition)
  114. instantiate_link(out_model, "T2P", "", new_transition, new_model)
  115. // Check if there is a Next to this Event, meaning another event
  116. if (read_nr_out(allOutgoingAssociationInstances(in_model, current_activity, "Next")) > 0):
  117. // We have a Next, so just push that next event on the options
  118. current_activity = set_pop(allAssociationDestinations(in_model, current_activity, "Next"))
  119. list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
  120. set_add(branches, create_tuple(new_model, options))
  121. else:
  122. // No Next in this node, so we recurse up until one of these elements does have a next (or we reach the top)
  123. while (read_nr_out(allOutgoingAssociationInstances(in_model, current_activity, "Next")) == 0):
  124. // Recurse up
  125. containers = allAssociationOrigins(in_model, current_activity, "Contains")
  126. if (read_nr_out(containers) == 1):
  127. current_activity = set_pop(containers)
  128. elif (read_nr_out(containers) == 0):
  129. // No more containers, so at top element
  130. break!
  131. if (read_nr_out(containers) == 0):
  132. // Nothing left to do, so clear up this branch, but continue with the others
  133. continue!
  134. else:
  135. // Found a node with a Next link: we follow it
  136. current_activity = set_pop(allAssociationDestinations(in_model, current_activity, "Next"))
  137. list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
  138. set_add(branches, create_tuple(new_model, options))
  139. elif (type == "Sequence"):
  140. // Process a sequence: just move the current option to the enclosing activity
  141. inner_elements = allAssociationDestinations(in_model, current_activity, "Contains")
  142. while (read_nr_out(inner_elements) > 0):
  143. element = set_pop(inner_elements)
  144. if (read_nr_out(allIncomingAssociationInstances(in_model, element, "Next")) == 0):
  145. current_activity = element
  146. break!
  147. // current_activity now contains the inner element to execute
  148. list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
  149. // keep the current branch alive, as everything is updated by reference
  150. set_add(branches, branch)
  151. elif (type == "Parallel"):
  152. // Process a parallel: create new options for each containing element
  153. inner_elements = allAssociationDestinations(in_model, current_activity, "Contains")
  154. while (read_nr_out(inner_elements) > 0):
  155. current_activity = set_pop(inner_elements)
  156. // current_activity now contains the inner element to execute in parallel (an option)
  157. list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
  158. // keep the current branch alive, as everything is updated by reference
  159. set_add(branches, branch)
  160. elif (type == "Alternative"):
  161. inner_elements = allAssociationDestinations(in_model, current_activity, "Contains")
  162. while (read_nr_out(inner_elements) > 0):
  163. current_activity = set_pop(inner_elements)
  164. // current_activity now contains the inner element to execute in alternative branches (a branch)
  165. new_options = set_copy(options)
  166. list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
  167. set_add(branches, create_tuple(previous_place, new_options))
  168. dict_add(result, "Encapsulated_PetriNet", out_model)
  169. return result!