environment_to_EPN.alc 7.6 KB

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