reachability.alc 6.4 KB

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