pm_library.mvc 11 KB

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