reachability.alc 6.2 KB

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