reachability.alc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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 state
  21. String name
  22. String link
  23. String place
  24. String key
  25. Integer link_weight
  26. Integer initial
  27. Integer state_id
  28. Integer next_id
  29. Boolean possible
  30. Element all_places
  31. Element dict_repr
  32. Element work_unit
  33. result = create_node()
  34. out_model = instantiate_model(output_mms["ReachabilityGraph"])
  35. in_model = params["PetriNet"]
  36. log("Got in_model: " + cast_e2s(in_model))
  37. log("Params: " + dict_to_string(params))
  38. log("Params: " + cast_e2s(in_model))
  39. log("Keys in type: " + set_to_string(dict_keys(in_model["metamodel"]["model"])))
  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. log("Got all transitions: " + set_to_string(all_transitions))
  45. while (read_nr_out(all_transitions) > 0):
  46. transition = set_pop(all_transitions)
  47. tv = create_node()
  48. links = allIncomingAssociationInstances(in_model, transition, "P2T")
  49. log("All links: " + set_to_string(links))
  50. while (read_nr_out(links) > 0):
  51. link = set_pop(links)
  52. name = reverseKeyLookup(in_model["model"], read_edge_src(in_model["model"][link]))
  53. link_weight = read_attribute(in_model, link, "weight")
  54. dict_add(tv, name, link_weight)
  55. dict_add(transition_vectors_consume, transition, tv)
  56. log("Consume OK: " + dict_to_string(transition_vectors_consume[transition]))
  57. tv = create_node()
  58. links = allOutgoingAssociationInstances(in_model, transition, "T2P")
  59. while (read_nr_out(links) > 0):
  60. link = set_pop(links)
  61. name = reverseKeyLookup(in_model["model"], read_edge_dst(in_model["model"][link]))
  62. link_weight = read_attribute(in_model, link, "weight")
  63. dict_add(tv, name, link_weight)
  64. dict_add(transition_vectors_produce, transition, tv)
  65. log("Produce OK: " + dict_to_string(transition_vectors_produce[transition]))
  66. log("Ready for work!")
  67. workset = create_node()
  68. all_places = allInstances(in_model, "Place")
  69. log("All places: " + set_to_string(all_places))
  70. dict_repr = create_node()
  71. while (read_nr_out(all_places) > 0):
  72. place = set_pop(all_places)
  73. dict_add(dict_repr, place, read_attribute(in_model, place, "tokens"))
  74. log("Representation of first state: " + dict_to_string(dict_repr))
  75. all_transitions_original = allInstances(in_model, "Transition")
  76. mappings = create_node()
  77. state_id = 0
  78. next_id = 1
  79. reachable_states = create_node()
  80. dict_add(reachable_states, state_id, dict_repr)
  81. dict_add(mappings, state_id, create_node())
  82. set_add(workset, state_id)
  83. while (read_nr_out(workset) > 0):
  84. state_id = set_pop(workset)
  85. // TODO check if dict_repr is already in the set of reachable states
  86. dict_repr = reachable_states[state_id]
  87. // Compute how the PN behaves with this specific state
  88. // For this, we fetch all transitions and check if they are enabled
  89. all_transitions = set_copy(all_transitions_original)
  90. while (read_nr_out(all_transitions) > 0):
  91. transition = set_pop(all_transitions)
  92. log("Compute if possible for " + transition)
  93. keys = dict_keys(transition_vectors_consume[transition])
  94. possible = True
  95. while (read_nr_out(keys) > 0):
  96. key = set_pop(keys)
  97. // Compare the values in the state with those consumed by the transition
  98. if (integer_lt(dict_repr[key], transition_vectors_consume[transition][key])):
  99. // Impossible transition, so discard this one
  100. possible = False
  101. break!
  102. if (possible):
  103. dict_repr = dict_copy(dict_repr)
  104. // Transition can execute, so compute and add the new state based on the consume/produce vectors
  105. keys = dict_keys(transition_vectors_consume[transition])
  106. log("Deduct")
  107. while (read_nr_out(keys) > 0):
  108. key = set_pop(keys)
  109. dict_overwrite(dict_repr, key, integer_subtraction(dict_repr[key], transition_vectors_consume[transition][key]))
  110. keys = dict_keys(transition_vectors_produce[transition])
  111. log("Increment")
  112. while (read_nr_out(keys) > 0):
  113. key = set_pop(keys)
  114. dict_overwrite(dict_repr, key, integer_addition(dict_repr[key], transition_vectors_produce[transition][key]))
  115. // Add the target to workset, as it is new
  116. dict_add(reachable_states, next_id, dict_repr)
  117. dict_add(mappings, next_id, create_node())
  118. dict_add(mappings[state_id], transition, next_id)
  119. set_add(workset, next_id)
  120. next_id = next_id + 1
  121. dict_add(result, "ReachabilityGraph", out_model)
  122. return result!