pm_library.mvc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. AtomicDEVSBlock ResourceHandler {
  2. name = "ResourceHandler"
  3. parameters = 1
  4. initialState = "self.state, self.elapsed = {'resources': parameters[0], 'queue': []}, 0.0"
  5. timeAdvance = """
  6. if self.state['queue'] and self.state['resources']:
  7. # Can grant a resource
  8. return 0.0
  9. else:
  10. # No request queued, or no available resources to handle the request
  11. return float('inf')
  12. """
  13. outputFnc = """
  14. return {self.resource_out: {'id': self.state['queue'][0]}}
  15. """
  16. intTransition = """
  17. # Processed a request that could be processed
  18. self.state['resources'] -= 1
  19. del self.state['queue'][0]
  20. return self.state
  21. """
  22. extTransition = """
  23. for inp in inputs[self.resource_in]:
  24. if inp['type'] == 'request':
  25. # Queue the request
  26. self.state['queue'].append(inp['id'])
  27. elif inp['type'] == 'release':
  28. # Increment the number of available resources
  29. self.state['resources'] += 1
  30. return self.state
  31. """
  32. }
  33. InputPort rh_ri {
  34. name = "resource_in"
  35. }
  36. OutputPort rh_ro {
  37. name = "resource_out"
  38. }
  39. DEVSBlockToPort (ResourceHandler, rh_ri) {}
  40. DEVSBlockToPort (ResourceHandler, rh_ro) {}
  41. AtomicDEVSBlock Activity {
  42. name = "Activity"
  43. parameters = 2
  44. initialState = """
  45. class ActivityState(object):
  46. def __init__(self, name, distribution):
  47. self.timer = float('inf')
  48. self.mode = 'inactive'
  49. self.counter = 0
  50. self.name = name
  51. self.distribution = distribution
  52. def __str__(self):
  53. return str(vars(self))
  54. def random_sample(self):
  55. return self.distribution(self.counter)
  56. self.state, self.elapsed = ActivityState(parameters[0], parameters[1]), 0.0
  57. """
  58. timeAdvance = """
  59. return self.state.timer
  60. """
  61. outputFnc = """
  62. if self.state.mode == 'active':
  63. # Output the control token to the next model in line, and release the resources
  64. return {self.control_out: {}, self.resource_out: [{'type': 'release'}]}
  65. elif self.state.mode == 'request_resource':
  66. # Output a request for resources with a specified ID (used to find out whether this was our request)
  67. return {self.resource_out: [{'type': 'request', 'id': '%s-%s' % (self.state.name, self.state.counter)}]}
  68. else:
  69. return {}
  70. """
  71. intTransition = """
  72. self.state.timer -= self.timeAdvance()
  73. if self.state.mode == 'request_resource':
  74. # Go and request the required resource
  75. self.state.mode = 'wait_resource'
  76. self.state.timer = float('inf')
  77. elif self.state.mode == 'active':
  78. # Finished execution, so release resources
  79. self.state.mode = 'inactive'
  80. self.state.timer = 0.0
  81. self.state.timer = float('inf')
  82. self.state.counter += 1
  83. return self.state
  84. """
  85. extTransition = """
  86. self.state.timer -= self.elapsed
  87. if self.state.mode == 'inactive' and self.control_in in inputs:
  88. # Got control token, so ask for the required resources
  89. self.state.mode = 'request_resource'
  90. self.state.timer = 0.0
  91. # NOTE this violates DEVS, though is easy to debug
  92. #print('Activate ' + str(self.state.name) + ' at time ' + str(self.time_last[0] + self.elapsed))
  93. elif self.state.mode == 'wait_resource' and self.resource_in in inputs and inputs[self.resource_in]['id'] == '%s-%s' % (self.state.name, self.state.counter):
  94. # Got required resources, so start execution
  95. self.state.mode = 'active'
  96. self.state.timer = self.state.random_sample()
  97. return self.state
  98. """
  99. }
  100. InputPort act_ri {
  101. name = "resource_in"
  102. }
  103. OutputPort act_ro {
  104. name = "resource_out"
  105. }
  106. DEVSBlockToPort (Activity, act_ri) {}
  107. DEVSBlockToPort (Activity, act_ro) {}
  108. AtomicDEVSBlock ParallelSplit {
  109. name = "ParallelSplit"
  110. parameters = 0
  111. initialState = "self.state, self.elapsed = False, 0.0"
  112. timeAdvance = """
  113. if self.state:
  114. return 0.0
  115. else:
  116. return float('inf')
  117. """
  118. outputFnc = """
  119. return {self.control_out: {}}
  120. """
  121. intTransition = """
  122. return False
  123. """
  124. extTransition = """
  125. return True
  126. """
  127. }
  128. InputPort split_ci {
  129. name = "control_in"
  130. }
  131. OutputPort split_co {
  132. name = "control_out"
  133. }
  134. DEVSBlockToPort (ParallelSplit, split_ci) {}
  135. DEVSBlockToPort (ParallelSplit, split_co) {}
  136. AtomicDEVSBlock Synchronization {
  137. name = "Synchronization"
  138. parameters = 1
  139. initialState = "self.state, self.elapsed = {'current': parameters[0], 'max': parameters[0]}, 0.0"
  140. timeAdvance = """
  141. if self.state['current'] == 0:
  142. return 0.0
  143. else:
  144. return float('inf')
  145. """
  146. outputFnc = """
  147. return {self.control_out: {}}
  148. """
  149. intTransition = """
  150. self.state['current'] = self.state['max']
  151. return self.state
  152. """
  153. extTransition = """
  154. self.state['current'] -= 1
  155. return self.state
  156. """
  157. }
  158. InputPort syn_ci {
  159. name = "control_in"
  160. }
  161. OutputPort syn_co {
  162. name = "control_out"
  163. }
  164. DEVSBlockToPort (Synchronization, syn_ci) {}
  165. DEVSBlockToPort (Synchronization, syn_co) {}
  166. AtomicDEVSBlock ExclusiveChoice {
  167. name = "ExclusiveChoice"
  168. parameters = 1
  169. initialState = """
  170. class ExclusiveChoiceState(object):
  171. def __init__(self, distribution):
  172. self.counter = 0
  173. self.choice = None
  174. self.distribution = distribution
  175. def __str__(self):
  176. return str(vars(self))
  177. def make_choice(self):
  178. return self.distribution(self.counter)
  179. self.state, self.elapsed = ExclusiveChoiceState(parameters[0]), 0.0
  180. """
  181. timeAdvance = """
  182. if self.state.choice is not None:
  183. return 0.0
  184. else:
  185. return float('inf')
  186. """
  187. outputFnc = """
  188. if self.state.choice == 0:
  189. return {self.control_out1: {}}
  190. else:
  191. return {self.control_out2: {}}
  192. """
  193. intTransition = """
  194. self.state.choice = None
  195. self.state.counter += 1
  196. return self.state
  197. """
  198. extTransition = """
  199. # Got a control token, so have to make a choice
  200. self.state.choice = self.state.make_choice()
  201. return self.state
  202. """
  203. }
  204. InputPort xor_ci {
  205. name = "control_in"
  206. }
  207. OutputPort xor_co1 {
  208. name = "control_out1"
  209. }
  210. OutputPort xor_co2 {
  211. name = "control_out2"
  212. }
  213. DEVSBlockToPort (ExclusiveChoice, xor_ci) {}
  214. DEVSBlockToPort (ExclusiveChoice, xor_co1) {}
  215. DEVSBlockToPort (ExclusiveChoice, xor_co2) {}
  216. AtomicDEVSBlock SimpleMerge {
  217. name = "SimpleMerge"
  218. parameters = 0
  219. initialState = "self.state, self.elapsed = False, 0.0"
  220. timeAdvance = """
  221. if self.state:
  222. return 0.0
  223. else:
  224. return float('inf')
  225. """
  226. outputFnc = """
  227. return {self.control_out: {}}
  228. """
  229. intTransition = """
  230. return False
  231. """
  232. extTransition = """
  233. return True
  234. """
  235. }
  236. InputPort or_ci {
  237. name = "control_in"
  238. }
  239. OutputPort or_co {
  240. name = "control_out"
  241. }
  242. DEVSBlockToPort (SimpleMerge, or_ci) {}
  243. DEVSBlockToPort (SimpleMerge, or_co) {}
  244. AtomicDEVSBlock MultiInstance {
  245. name = "MultiInstance"
  246. parameters = 2
  247. initialState = """
  248. class MultiInstanceState(object):
  249. def __init__(self, name, num, distribution):
  250. self.spawned = num
  251. self.collected = 0
  252. self.counter = 0
  253. self.mode = 'inactive'
  254. self.running_tasks = []
  255. self.requested = []
  256. self.name = name
  257. self.distribution = distribution
  258. def __str__(self):
  259. return str(vars(self))
  260. def task_time(self):
  261. return self.distribution(self.counter)
  262. self.state, self.elapsed = MultiInstanceState(parameters[0], parameters[1], parameters[2])
  263. """
  264. timeAdvance = """
  265. if self.state.mode == 'finish':
  266. return 0.0
  267. elif self.state.running_tasks:
  268. return self.state.running_tasks[0][0]
  269. elif self.state.mode == 'request_resources':
  270. return 0.0
  271. else:
  272. return float('inf')
  273. """
  274. outputFnc = """
  275. if self.state.mode == 'request_resources':
  276. # Request all resources in one go
  277. return {self.resource_out: [{'type': 'request', 'id': i} for i in self.state.requested]}
  278. elif self.state.mode == 'active':
  279. # Finished an instance, so release it
  280. return {self.resource_out: [{'type': 'release'}]}
  281. elif self.state.mode == 'finish':
  282. # Finished execution of all, so pass on token
  283. return {self.control_out: {}}
  284. else:
  285. return {}
  286. """
  287. intTransition = """
  288. ta = self.timeAdvance()
  289. for t in self.state.running_tasks:
  290. t[0] -= ta
  291. if self.state.mode == 'active':
  292. # Finished an instance, so pop it
  293. del self.state.running_tasks[0]
  294. self.state.collected += 1
  295. if self.state.collected == self.state.spawned:
  296. self.state.mode = 'finish'
  297. elif self.state.mode == 'request_resources':
  298. # Requested resources, so be ready for a response
  299. self.state.mode = 'active'
  300. elif self.state.mode == 'finish':
  301. self.state.mode = 'inactive'
  302. self.state.collected = 0
  303. self.state.counter += 1
  304. self.state.running_tasks = []
  305. return self.state
  306. """
  307. extTransition = """
  308. # Got input, so have to spawn #num of them
  309. for t in self.state.running_tasks:
  310. t[0] -= self.elapsed
  311. if self.state.mode == 'inactive' and self.control_in in inputs:
  312. self.state.mode = 'request_resources'
  313. self.state.requested = ['%s-%s-%s' % (self.state.name, self.state.counter, i) for i in range(self.state.spawned)]
  314. if self.state.mode in ['active', 'release_resource'] and self.resource_in in inputs:
  315. # Got a resource, so allocate it to an activity
  316. self.state.running_tasks.append([self.state.task_time(), self.state.requested.pop(0)])
  317. # NOTE this violates DEVS, though is easy to debug
  318. #print('Spawn ' + str(self.state.running_tasks[-1][1]) + ' at time ' + str(self.time_last[0] + self.elapsed))
  319. self.state.running_tasks.sort()
  320. return self.state
  321. """
  322. }
  323. InputPort mi_ci {
  324. name = "control_in"
  325. }
  326. OutputPort mi_co {
  327. name = "control_out"
  328. }
  329. InputPort mi_ri {
  330. name = "resource_in"
  331. }
  332. OutputPort mi_ro {
  333. name = "resource_out"
  334. }
  335. DEVSBlockToPort (MultiInstance, mi_ci) {}
  336. DEVSBlockToPort (MultiInstance, mi_co) {}
  337. DEVSBlockToPort (MultiInstance, mi_ri) {}
  338. DEVSBlockToPort (MultiInstance, mi_ro) {}