models.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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 = ```
  85. errors = []
  86. numShips = get_slot_value(this, "numShips")
  87. status = get_slot_value(this, "status")
  88. if (numShips == 0) != (status == "empty"):
  89. errors.append(f"Inconsistent: numShips = {numShips}, but status = {status}")
  90. errors
  91. ```;
  92. }
  93. :Inheritance (BerthState -> PlaceState)
  94. BerthState_status:AttributeLink (BerthState -> String) {
  95. name = "status";
  96. optional = False;
  97. constraint = `(
  98. get_value(get_target(this)) in { "empty", "unserved", "served" }
  99. )`;
  100. }
  101. WorkerSetState:Class
  102. :Inheritance (WorkerSetState -> State)
  103. isOperating:Association (WorkerSetState -> Berth) {
  104. constraint = ```
  105. errors = []
  106. # get status of Berth
  107. berth = get_target(this)
  108. berth_state = get_source(get_incoming(berth, "of")[0])
  109. status = get_slot_value(berth_state, "status")
  110. if status != "unserved":
  111. errors.append(f"Cannot operate {get_name(berth)} because there is no unserved ship there.")
  112. # only operate Berts that we can operate
  113. workerset = get_target(get_outgoing(get_source(this), "of")[0])
  114. can_operate = [get_target(lnk) for lnk in get_outgoing(workerset, "canOperate")]
  115. if berth not in can_operate:
  116. errors.append(f"Cannot operate {get_name(berth)}.")
  117. errors
  118. ```;
  119. }
  120. operatingCapacities:GlobalConstraint {
  121. constraint = ```
  122. errors = []
  123. for _, workersetstate in get_all_instances("WorkerSetState"):
  124. workerset = get_target(get_outgoing(workersetstate, "of")[0])
  125. num_operating = len(get_outgoing(workersetstate, "isOperating"))
  126. num_workers = get_slot_value(workerset, "numWorkers")
  127. if num_operating > num_workers:
  128. errors.append(f"WorkerSet {get_name(workerset)} is operating more berths ({num_operating}) than there are workers ({num_workers})")
  129. errors
  130. ```;
  131. }
  132. ConnectionState:Class
  133. :Inheritance (ConnectionState -> State)
  134. ConnectionState_moved:AttributeLink (ConnectionState -> Boolean) {
  135. name = "moved";
  136. optional = False;
  137. constraint = ```
  138. result = True
  139. all_successors_moved = True
  140. moved = get_value(get_target(this))
  141. conn_state = get_source(this)
  142. conn = get_target(get_outgoing(conn_state, "of")[0])
  143. tgt_place = get_target(conn)
  144. next_conns = get_outgoing(tgt_place, "connection")
  145. for next_conn in next_conns:
  146. next_conn_state = get_source(get_incoming(next_conn, "of")[0])
  147. if not get_slot_value(next_conn_state, "moved"):
  148. all_successors_moved = False
  149. if moved and not all_successors_moved:
  150. result = f"Connection {get_name(conn)} played before its turn."
  151. result
  152. ```;
  153. }
  154. Clock:Class {
  155. lower_cardinality = 1;
  156. upper_cardinality = 1;
  157. }
  158. Clock_time:AttributeLink (Clock -> Integer) {
  159. name = "time";
  160. optional = False;
  161. constraint = `get_value(get_target(this)) >= 0`;
  162. }
  163. """
  164. # Design model: the part that doesn't change
  165. port_m_cs = """
  166. gen:Generator
  167. # newly arrive ships collect here
  168. waiting:Place
  169. c1:connection (gen -> waiting)
  170. inboundPassage:Place
  171. c2:connection (waiting -> inboundPassage)
  172. outboundPassage:Place
  173. # inboundPassage and outboundPassage cannot have more than 3 ships total
  174. passageCap:CapacityConstraint {
  175. shipCapacity = 3;
  176. }
  177. :capacityOf (passageCap -> inboundPassage)
  178. :capacityOf (passageCap -> outboundPassage)
  179. # Berth 1
  180. inboundBerth1:Place
  181. berth1:Berth
  182. outboundBerth1:Place
  183. inboundBerth1Cap:CapacityConstraint { shipCapacity = 1; }
  184. :capacityOf (inboundBerth1Cap -> inboundBerth1)
  185. outboundBerth1Cap:CapacityConstraint { shipCapacity = 1; }
  186. :capacityOf (outboundBerth1Cap -> outboundBerth1)
  187. berth1Cap:CapacityConstraint { shipCapacity = 1; }
  188. :capacityOf (berth1Cap -> berth1)
  189. c3:connection (inboundBerth1 -> berth1)
  190. c4:connection (berth1 -> outboundBerth1)
  191. # Berth 2
  192. inboundBerth2:Place
  193. berth2:Berth
  194. outboundBerth2:Place
  195. inboundBerth2Cap:CapacityConstraint { shipCapacity = 1; }
  196. :capacityOf (inboundBerth2Cap -> inboundBerth2)
  197. outboundBerth2Cap:CapacityConstraint { shipCapacity = 1; }
  198. :capacityOf (outboundBerth2Cap -> outboundBerth2)
  199. berth2Cap:CapacityConstraint { shipCapacity = 1; }
  200. :capacityOf (berth2Cap -> berth2)
  201. c5:connection (inboundBerth2 -> berth2)
  202. c6:connection (berth2 -> outboundBerth2)
  203. # can either go to Berth 1 or Berth 2
  204. c7:connection (inboundPassage -> inboundBerth1)
  205. c8:connection (inboundPassage -> inboundBerth2)
  206. c9:connection (outboundBerth1 -> outboundPassage)
  207. c10:connection (outboundBerth2 -> outboundPassage)
  208. # ships that have been served are counted here
  209. served:Place
  210. c11:connection (outboundPassage -> served)
  211. workers:WorkerSet {
  212. numWorkers = 1;
  213. }
  214. :canOperate (workers -> berth1)
  215. :canOperate (workers -> berth2)
  216. """
  217. # Initial runtime model: the part that changes (every execution step)
  218. port_rt_m_cs = port_m_cs + """
  219. clock:Clock {
  220. time = 0;
  221. }
  222. waitingState:PlaceState { numShips = 0; } :of (waitingState -> waiting)
  223. inboundPassageState:PlaceState { numShips = 0; } :of (inboundPassageState -> inboundPassage)
  224. outboundPassageState:PlaceState { numShips = 0; } :of (outboundPassageState -> outboundPassage)
  225. inboundBerth1State:PlaceState { numShips = 0; } :of (inboundBerth1State -> inboundBerth1)
  226. outboundBerth1State:PlaceState { numShips = 0; } :of (outboundBerth1State -> outboundBerth1)
  227. inboundBerth2State:PlaceState { numShips = 0; } :of (inboundBerth2State -> inboundBerth2)
  228. outboundBerth2State:PlaceState { numShips = 0; } :of (outboundBerth2State -> outboundBerth2)
  229. berth1State:BerthState { status = "empty"; numShips = 0; } :of (berth1State -> berth1)
  230. berth2State:BerthState { status = "empty"; numShips = 0; } :of (berth2State -> berth2)
  231. servedState:PlaceState { numShips = 0; } :of (servedState -> served)
  232. workersState:WorkerSetState :of (workersState -> workers)
  233. c1S:ConnectionState { moved = False; } :of (c1S -> c1)
  234. c2S:ConnectionState { moved = False; } :of (c2S -> c2)
  235. c3S:ConnectionState { moved = False; } :of (c3S -> c3)
  236. c4S:ConnectionState { moved = False; } :of (c4S -> c4)
  237. c5S:ConnectionState { moved = False; } :of (c5S -> c5)
  238. c6S:ConnectionState { moved = False; } :of (c6S -> c6)
  239. c7S:ConnectionState { moved = False; } :of (c7S -> c7)
  240. c8S:ConnectionState { moved = False; } :of (c8S -> c8)
  241. c9S:ConnectionState { moved = False; } :of (c9S -> c9)
  242. c10S:ConnectionState { moved = False; } :of (c10S -> c10)
  243. c11S:ConnectionState { moved = False; } :of (c11S -> c11)
  244. """