reachability_subfunction.alc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. include "primitives.alh"
  2. include "modelling.alh"
  3. include "object_operations.alh"
  4. Boolean function main(model : Element):
  5. Element workset
  6. Element transition_vectors_produce
  7. Element transition_vectors_consume
  8. Element all_transitions
  9. Element all_transitions_original
  10. Element tv
  11. Element links
  12. Element mappings
  13. Element reachable_states
  14. Element keys
  15. String transition
  16. String new_transition
  17. String state
  18. String name
  19. String link
  20. String place
  21. String key
  22. Integer link_weight
  23. Integer initial
  24. Integer state_id
  25. Integer next_id
  26. Boolean possible
  27. Element all_places
  28. Element dict_repr
  29. Element new_dict_repr
  30. Element work_unit
  31. Element cache
  32. cache = create_node()
  33. // Create a dictionary representation for each transition
  34. transition_vectors_produce = create_node()
  35. transition_vectors_consume = create_node()
  36. all_transitions = allInstances(model, "PetriNet/Transition")
  37. while (read_nr_out(all_transitions) > 0):
  38. transition = set_pop(all_transitions)
  39. tv = create_node()
  40. links = allIncomingAssociationInstances(model, transition, "PetriNet/P2T")
  41. while (read_nr_out(links) > 0):
  42. link = set_pop(links)
  43. name = reverseKeyLookup(model["model"], read_edge_src(model["model"][link]))
  44. link_weight = read_attribute(model, link, "weight")
  45. dict_add_fast(tv, name, link_weight)
  46. dict_add_fast(transition_vectors_consume, transition, tv)
  47. tv = create_node()
  48. links = allOutgoingAssociationInstances(model, transition, "PetriNet/T2P")
  49. while (read_nr_out(links) > 0):
  50. link = set_pop(links)
  51. name = reverseKeyLookup(model["model"], read_edge_dst(model["model"][link]))
  52. link_weight = read_attribute(model, link, "weight")
  53. dict_add_fast(tv, name, link_weight)
  54. dict_add_fast(transition_vectors_produce, transition, tv)
  55. workset = create_node()
  56. all_places = allInstances(model, "PetriNet/Place")
  57. dict_repr = create_node()
  58. while (read_nr_out(all_places) > 0):
  59. place = set_pop(all_places)
  60. dict_add_fast(dict_repr, place, read_attribute(model, place, "tokens"))
  61. all_transitions_original = allInstances(model, "PetriNet/Transition")
  62. mappings = create_node()
  63. state_id = 0
  64. next_id = 1
  65. reachable_states = create_node()
  66. dict_add_fast(reachable_states, state_id, dict_repr)
  67. dict_add_fast(mappings, state_id, create_node())
  68. set_add(workset, state_id)
  69. // And add in the model itself
  70. state = create_state(model, cast_string(state_id), dict_repr, cache, True)
  71. while (read_nr_out(workset) > 0):
  72. state_id = set_pop(workset)
  73. dict_repr = reachable_states[state_id]
  74. // Compute how the PN behaves with this specific state
  75. // For this, we fetch all transitions and check if they are enabled
  76. all_transitions = set_copy(all_transitions_original)
  77. while (read_nr_out(all_transitions) > 0):
  78. transition = set_pop(all_transitions)
  79. keys = dict_keys(transition_vectors_consume[transition])
  80. possible = True
  81. while (read_nr_out(keys) > 0):
  82. key = set_pop(keys)
  83. // Compare the values in the state with those consumed by the transition
  84. if (integer_lt(dict_repr[key], transition_vectors_consume[transition][key])):
  85. // Impossible transition, so discard this one
  86. possible = False
  87. break!
  88. if (possible):
  89. new_dict_repr = dict_copy(dict_repr)
  90. // Transition can execute, so compute and add the new state based on the consume/produce vectors
  91. keys = dict_keys(transition_vectors_consume[transition])
  92. while (read_nr_out(keys) > 0):
  93. key = set_pop(keys)
  94. dict_overwrite(new_dict_repr, key, integer_subtraction(new_dict_repr[key], transition_vectors_consume[transition][key]))
  95. keys = dict_keys(transition_vectors_produce[transition])
  96. while (read_nr_out(keys) > 0):
  97. key = set_pop(keys)
  98. dict_overwrite(new_dict_repr, key, integer_addition(new_dict_repr[key], transition_vectors_produce[transition][key]))
  99. // Check if this state already has an associated ID
  100. Integer other_state_id
  101. Integer target_id
  102. keys = dict_keys(reachable_states)
  103. target_id = -1
  104. Float start
  105. while (read_nr_out(keys) > 0):
  106. other_state_id = set_pop(keys)
  107. if (dict_eq(reachable_states[other_state_id], new_dict_repr)):
  108. target_id = other_state_id
  109. break!
  110. if (target_id == -1):
  111. // New state
  112. target_id = next_id
  113. next_id = next_id + 1
  114. // Add to all data structures
  115. dict_add_fast(reachable_states, target_id, new_dict_repr)
  116. dict_add_fast(mappings, target_id, create_node())
  117. set_add(workset, target_id)
  118. // And add in the model itself
  119. create_state(model, cast_string(target_id), new_dict_repr, cache, False)
  120. // Anyway, we have found a transition, which we should store
  121. dict_add_fast(mappings[state_id], transition, target_id)
  122. // And also store it in the model itself
  123. new_transition = instantiate_link(model, "ReachabilityGraph/Transition", "", cast_string(state_id), cast_string(target_id))
  124. instantiate_attribute(model, new_transition, "name", read_attribute(model, transition, "name"))
  125. log("# reachable states: " + cast_string(next_id))
  126. return True!
  127. String function create_state(model : Element, name : String, dict_repr : Element, cache : Element, initial : Boolean):
  128. Element state
  129. Element keys
  130. Element sub
  131. String key
  132. String place
  133. if (initial):
  134. state = instantiate_node(model, "ReachabilityGraph/InitialState", name)
  135. else:
  136. state = instantiate_node(model, "ReachabilityGraph/State", name)
  137. instantiate_attribute(model, state, "name", name)
  138. instantiate_attribute(model, state, "error", False)
  139. keys = dict_keys(dict_repr)
  140. while (read_nr_out(keys) > 0):
  141. key = set_pop(keys)
  142. name = read_attribute(model, key, "name")
  143. if (bool_not(dict_in(cache, name))):
  144. dict_add_fast(cache, name, create_node())
  145. sub = cache[name]
  146. if (bool_not(dict_in(sub, dict_repr[key]))):
  147. place = instantiate_node(model, "ReachabilityGraph/Place", "")
  148. instantiate_attribute(model, place, "name", name)
  149. instantiate_attribute(model, place, "tokens", dict_repr[key])
  150. dict_add_fast(sub, dict_repr[key], place)
  151. else:
  152. place = sub[dict_repr[key]]
  153. instantiate_link(model, "ReachabilityGraph/Contains", "", state, place)
  154. return state!