models.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. # Design meta-model
  2. port_mm_cs = """
  3. Source:Class {
  4. abstract = True;
  5. }
  6. Sink:Class {
  7. abstract = True;
  8. }
  9. Place:Class
  10. :Inheritance (Place -> Source)
  11. :Inheritance (Place -> Sink)
  12. connection:Association (Source -> Sink)
  13. CapacityConstraint:Class
  14. CapacityConstraint_shipCapacity:AttributeLink (CapacityConstraint -> Integer) {
  15. name = "shipCapacity";
  16. optional = False;
  17. # cannot have negative capacity:
  18. constraint = `get_value(get_target(this)) >= 0`; # non-negative
  19. }
  20. # Capacity
  21. capacityOf:Association (CapacityConstraint -> Place) {
  22. # must say something about at least one Place, otherwise what is the point of the constraint?
  23. target_lower_cardinality = 1;
  24. }
  25. Berth:Class
  26. :Inheritance (Berth -> Place)
  27. # Set of workers
  28. WorkerSet:Class
  29. WorkerSet_numWorkers:AttributeLink (WorkerSet -> Integer) {
  30. name = "numWorkers";
  31. optional = False;
  32. constraint = `get_value(get_target(this)) >= 0`; # non-negative
  33. }
  34. canOperate:Association (WorkerSet -> Berth) {
  35. target_lower_cardinality = 1;
  36. }
  37. Generator:Class
  38. :Inheritance (Generator -> Source)
  39. # Those classes to which we want to attach a runtime state object
  40. Stateful:Class {
  41. abstract = True;
  42. }
  43. :Inheritance (Place -> Stateful)
  44. :Inheritance (WorkerSet -> Stateful)
  45. :Inheritance (Berth -> Stateful)
  46. :Inheritance (connection -> Stateful)
  47. """;
  48. # Runtime meta-model
  49. port_rt_mm_cs = port_mm_cs + """
  50. State:Class
  51. of:Association (State -> Stateful) {
  52. source_lower_cardinality = 1;
  53. source_upper_cardinality = 1;
  54. target_lower_cardinality = 1;
  55. target_upper_cardinality = 1;
  56. }
  57. PlaceState:Class
  58. :Inheritance (PlaceState -> State)
  59. PlaceState_numShips:AttributeLink (PlaceState -> Integer) {
  60. # number of ships currently in the place
  61. name = "numShips";
  62. optional = False;
  63. constraint = `get_value(get_target(this)) >= 0`; # non-negative
  64. }
  65. shipCapacities:GlobalConstraint {
  66. constraint = ```
  67. errors = []
  68. for _, constr in get_all_instances("CapacityConstraint"):
  69. cap = get_slot_value(constr, "shipCapacity")
  70. total = 0
  71. place_names = [] # for debugging
  72. for lnk in get_outgoing(constr, "capacityOf"):
  73. place = get_target(lnk)
  74. place_names.append(get_name(place))
  75. place_state = get_source(get_incoming(place, "of")[0])
  76. total += get_slot_value(place_state, "numShips")
  77. if total > cap:
  78. errors.append(f"The number of ships in places {','.join(place_names)} ({total}) exceeds the capacity ({cap}) of CapacityConstraint {get_name(constr)}.")
  79. errors
  80. ```;
  81. }
  82. BerthState:Class {
  83. # status == empty <=> numShips == 0
  84. constraint = `(get_slot_value(this, "numShips") == 0) == (get_slot_value(this, "status") == "empty")`;
  85. }
  86. :Inheritance (BerthState -> PlaceState)
  87. BerthState_status:AttributeLink (BerthState -> String) {
  88. name = "status";
  89. optional = False;
  90. constraint = `(
  91. get_value(get_target(this)) in { "empty", "unserved", "served" }
  92. )`;
  93. }
  94. WorkerSetState:Class
  95. :Inheritance (WorkerSetState -> State)
  96. isOperating:Association (WorkerSetState -> Berth) {
  97. constraint = ```
  98. errors = []
  99. # get status of Berth
  100. berth = get_target(this)
  101. berth_state = get_source(get_incoming(berth, "of")[0])
  102. status = get_slot_value(berth_state, "status")
  103. if status != "unserved":
  104. errors.append(f"Cannot operate {get_name(berth)} because there is no unserved ship there.")
  105. # only operate Berts that we can operate
  106. workerset = get_target(get_outgoing(get_source(this), "of")[0])
  107. can_operate = [get_target(lnk) for lnk in get_outgoing(workerset, "canOperate")]
  108. if berth not in can_operate:
  109. errors.append(f"Cannot operate {get_name(berth)}.")
  110. errors
  111. ```;
  112. }
  113. operatingCapacities:GlobalConstraint {
  114. constraint = ```
  115. errors = []
  116. for _, workersetstate in get_all_instances("WorkerSetState"):
  117. workerset = get_target(get_outgoing(workersetstate, "of")[0])
  118. num_operating = len(get_outgoing(workersetstate, "isOperating"))
  119. num_workers = get_slot_value(workerset, "numWorkers")
  120. if num_operating > num_workers:
  121. errors.append(f"WorkerSet {get_name(workerset)} is operating more berths ({num_operating}) than there are workers ({num_workers})")
  122. errors
  123. ```;
  124. }
  125. ConnectionState:Class
  126. :Inheritance (ConnectionState -> State)
  127. ConnectionState_moved:AttributeLink (ConnectionState -> Boolean) {
  128. name = "moved";
  129. optional = False;
  130. constraint = ```
  131. result = True
  132. all_successors_moved = True
  133. moved = get_value(get_target(this))
  134. conn_state = get_source(this)
  135. conn = get_target(get_outgoing(conn_state, "of")[0])
  136. tgt_place = get_target(conn)
  137. next_conns = get_outgoing(tgt_place, "connection")
  138. for next_conn in next_conns:
  139. next_conn_state = get_source(get_incoming(next_conn, "of")[0])
  140. if not get_slot_value(next_conn_state, "moved"):
  141. all_successors_moved = False
  142. if moved and not all_successors_moved:
  143. result = f"Connection {get_name(conn)} played before its turn."
  144. result
  145. ```;
  146. }
  147. Clock:Class {
  148. lower_cardinality = 1;
  149. upper_cardinality = 1;
  150. }
  151. Clock_time:AttributeLink (Clock -> Integer) {
  152. name = "time";
  153. optional = False;
  154. constraint = `get_value(get_target(this)) >= 0`;
  155. }
  156. """
  157. # Design model: the part that doesn't change
  158. port_m_cs = """
  159. gen:Generator
  160. # newly arrive ships collect here
  161. waiting:Place
  162. c1:connection (gen -> waiting)
  163. inboundPassage:Place
  164. c2:connection (waiting -> inboundPassage)
  165. outboundPassage:Place
  166. # inboundPassage and outboundPassage cannot have more than 3 ships total
  167. passageCap:CapacityConstraint {
  168. shipCapacity = 3;
  169. }
  170. :capacityOf (passageCap -> inboundPassage)
  171. :capacityOf (passageCap -> outboundPassage)
  172. # Berth 1
  173. inboundBerth1:Place
  174. berth1:Berth
  175. outboundBerth1:Place
  176. inboundBerth1Cap:CapacityConstraint { shipCapacity = 1; }
  177. :capacityOf (inboundBerth1Cap -> inboundBerth1)
  178. outboundBerth1Cap:CapacityConstraint { shipCapacity = 1; }
  179. :capacityOf (outboundBerth1Cap -> outboundBerth1)
  180. berth1Cap:CapacityConstraint { shipCapacity = 1; }
  181. :capacityOf (berth1Cap -> berth1)
  182. c3:connection (inboundBerth1 -> berth1)
  183. c4:connection (berth1 -> outboundBerth1)
  184. # Berth 2
  185. inboundBerth2:Place
  186. berth2:Berth
  187. outboundBerth2:Place
  188. inboundBerth2Cap:CapacityConstraint { shipCapacity = 1; }
  189. :capacityOf (inboundBerth2Cap -> inboundBerth2)
  190. outboundBerth2Cap:CapacityConstraint { shipCapacity = 1; }
  191. :capacityOf (outboundBerth2Cap -> outboundBerth2)
  192. berth2Cap:CapacityConstraint { shipCapacity = 1; }
  193. :capacityOf (berth2Cap -> berth2)
  194. c5:connection (inboundBerth2 -> berth2)
  195. c6:connection (berth2 -> outboundBerth2)
  196. # can either go to Berth 1 or Berth 2
  197. c7:connection (inboundPassage -> inboundBerth1)
  198. c8:connection (inboundPassage -> inboundBerth2)
  199. c9:connection (outboundBerth1 -> outboundPassage)
  200. c10:connection (outboundBerth2 -> outboundPassage)
  201. # ships that have been served are counted here
  202. served:Place
  203. c11:connection (outboundPassage -> served)
  204. workers:WorkerSet {
  205. numWorkers = 1;
  206. }
  207. :canOperate (workers -> berth1)
  208. :canOperate (workers -> berth2)
  209. """
  210. # Initial runtime model: the part that changes (every execution step)
  211. port_rt_m_cs = port_m_cs + """
  212. clock:Clock {
  213. time = 0;
  214. }
  215. waitingState:PlaceState { numShips = 0; } :of (waitingState -> waiting)
  216. inboundPassageState:PlaceState { numShips = 0; } :of (inboundPassageState -> inboundPassage)
  217. outboundPassageState:PlaceState { numShips = 0; } :of (outboundPassageState -> outboundPassage)
  218. inboundBerth1State:PlaceState { numShips = 0; } :of (inboundBerth1State -> inboundBerth1)
  219. outboundBerth1State:PlaceState { numShips = 0; } :of (outboundBerth1State -> outboundBerth1)
  220. inboundBerth2State:PlaceState { numShips = 0; } :of (inboundBerth2State -> inboundBerth2)
  221. outboundBerth2State:PlaceState { numShips = 0; } :of (outboundBerth2State -> outboundBerth2)
  222. berth1State:BerthState { status = "empty"; numShips = 0; } :of (berth1State -> berth1)
  223. berth2State:BerthState { status = "empty"; numShips = 0; } :of (berth2State -> berth2)
  224. servedState:PlaceState { numShips = 0; } :of (servedState -> served)
  225. workersState:WorkerSetState :of (workersState -> workers)
  226. c1S:ConnectionState { moved = False; } :of (c1S -> c1)
  227. c2S:ConnectionState { moved = False; } :of (c2S -> c2)
  228. c3S:ConnectionState { moved = False; } :of (c3S -> c3)
  229. c4S:ConnectionState { moved = False; } :of (c4S -> c4)
  230. c5S:ConnectionState { moved = False; } :of (c5S -> c5)
  231. c6S:ConnectionState { moved = False; } :of (c6S -> c6)
  232. c7S:ConnectionState { moved = False; } :of (c7S -> c7)
  233. c8S:ConnectionState { moved = False; } :of (c8S -> c8)
  234. c9S:ConnectionState { moved = False; } :of (c9S -> c9)
  235. c10S:ConnectionState { moved = False; } :of (c10S -> c10)
  236. c11S:ConnectionState { moved = False; } :of (c11S -> c11)
  237. """