trafficModels.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  1. import sys
  2. sys.path.append("../../../src/")
  3. from infinity import *
  4. from DEVS import *
  5. import random
  6. north = 0
  7. east = 1
  8. south = 2
  9. west = 3
  10. vertical = "02"
  11. horizontal = "13"
  12. dir_to_int = {'n': north, 'e': east, 's': south, 'w': west}
  13. int_to_dir = {north: 'n', east: 'e', south: 's', west: 'w'}
  14. class Car:
  15. def __init__(self, ID, v, v_pref, dv_pos_max, dv_neg_max, departure_time):
  16. self.ID = ID
  17. self.v_pref = v_pref
  18. self.dv_pos_max = dv_pos_max
  19. self.dv_neg_max = dv_neg_max
  20. self.departure_time = departure_time
  21. self.distance_travelled = 0
  22. self.remaining_x = 0
  23. self.v = v
  24. def __eq__(self, other):
  25. return (self.ID == other.ID and
  26. self.v_pref == other.v_pref and
  27. self.dv_pos_max == other.dv_pos_max and
  28. self.dv_neg_max == other.dv_neg_max and
  29. self.departure_time == other.departure_time and
  30. self.distance_travelled == other.distance_travelled and
  31. self.remaining_x == other.remaining_x and
  32. self.v == other.v)
  33. def __str__(self):
  34. return "Car: ID = " + str(self.ID) + ", v_pref = " + str(self.v_pref) + ", dv_pos_max = " + str(self.dv_pos_max) + ", dv_neg_max = " + str(self.dv_neg_max) + ", departure_time = " + str(self.departure_time) + ", distance_travelled = " + str(self.distance_travelled) + (", v = %3f" % self.v) + ", path = " + str(self.path)
  35. def copy(self):
  36. car = Car(self.ID, self.v, self.v_pref, self.dv_pos_max, self.dv_neg_max, self.departure_time)
  37. car.distance_travelled = self.distance_travelled
  38. car.remaining_x = self.remaining_x
  39. car.path = list(self.path)
  40. return car
  41. class Query:
  42. def __init__(self, ID):
  43. self.ID = ID
  44. self.direction = ''
  45. def __str__(self):
  46. return "Query: ID = " + str(self.ID)
  47. def __eq__(self, other):
  48. return (self.ID == other.ID and self.direction == other.direction)
  49. def copy(self):
  50. query = Query(self.ID)
  51. query.direction = self.direction
  52. return query
  53. class QueryAck:
  54. def __init__(self, ID, t_until_dep):
  55. self.ID = ID
  56. self.t_until_dep = t_until_dep
  57. def __str__(self):
  58. return "Query Ack: ID = " + str(self.ID) + ", t_until_dep = %.3f" % self.t_until_dep
  59. def __eq__(self, other):
  60. return (self.ID == other.ID and self.t_until_dep == other.t_until_dep)
  61. def copy(self):
  62. return QueryAck(self.ID, self.t_until_dep)
  63. class BuildingState:
  64. def __init__(self, IAT_min, IAT_max, path, name):
  65. self.currentTime = 0
  66. from randomGenerator import RandomGenerator
  67. seed = random.random()
  68. self.randomGenerator = RandomGenerator(seed)
  69. self.send_query_delay = self.randomGenerator.uniform(IAT_min, IAT_max)
  70. self.send_car_delay = INFINITY
  71. self.path = path
  72. if path == []:
  73. self.send_query_delay = INFINITY
  74. self.name = name
  75. self.send_query_id = int(name.split("_", 1)[1].split("_")[0]) * 1000 + int(name.split("_", 1)[1].split("_")[1])
  76. self.send_car_id = self.send_query_id
  77. self.next_v_pref = 0
  78. self.sent = 0
  79. def copy(self):
  80. new = BuildingState(0, 0, list(self.path), self.name)
  81. new.currentTime = self.currentTime
  82. new.send_query_delay = self.send_query_delay
  83. new.send_car_delay = self.send_car_delay
  84. new.send_query_id = self.send_query_id
  85. new.send_car_id = self.send_car_id
  86. new.next_v_pref = self.next_v_pref
  87. new.randomGenerator = self.randomGenerator.copy()
  88. new.sent = self.sent
  89. return new
  90. def __str__(self):
  91. if self.path != []:
  92. return "Residence: send_query_delay = %.3f, send_query_id = %s, send_car_delay = %.3f, send_car_id = %s" % (self.send_query_delay, self.send_query_id, self.send_car_delay, self.send_car_id)
  93. else:
  94. return "Commercial: waiting..."
  95. class Building(AtomicDEVS):
  96. def __init__(self, generator, district, path = [], IAT_min = 100, IAT_max = 100, v_pref_min = 15, v_pref_max = 15, dv_pos_max = 15, dv_neg_max = 150, name="Building"):
  97. # parent class constructor
  98. AtomicDEVS.__init__(self, name)
  99. # copy of arguments
  100. self.IAT_min = IAT_min
  101. self.IAT_max = IAT_max
  102. self.v_pref_min = v_pref_min
  103. self.v_pref_max = v_pref_max
  104. self.dv_pos_max = dv_pos_max
  105. self.dv_neg_max = dv_neg_max
  106. # output ports
  107. self.q_sans = self.addOutPort(name="q_sans")
  108. self.q_send = self.addOutPort(name="q_send")
  109. self.exit = self.addOutPort(name="exit")
  110. self.Q_send = self.q_send
  111. self.car_out = self.exit
  112. # input ports
  113. self.q_rans = self.addInPort(name="q_rans")
  114. #self.q_recv = self.addInPort(name="q_recv")
  115. self.Q_rack = self.q_rans
  116. self.entry = self.addInPort(name="entry")
  117. # set the state
  118. self.state = BuildingState(IAT_min, IAT_max, path, name)
  119. self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
  120. self.send_max = 1
  121. self.district = district
  122. def intTransition(self):
  123. mintime = self.timeAdvance()
  124. #print("Got mintime: " + str(mintime))
  125. self.state.currentTime += mintime
  126. self.state.send_query_delay -= mintime
  127. self.state.send_car_delay -= mintime
  128. if self.state.send_car_delay == 0:
  129. self.state.send_car_delay = INFINITY
  130. self.state.send_car_id = self.state.send_query_id
  131. self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
  132. elif self.state.send_query_delay == 0:
  133. self.state.send_query_delay = INFINITY
  134. return self.state
  135. def outputFnc(self):
  136. mintime = self.timeAdvance()
  137. #print("Got mintime: " + str(mintime))
  138. currentTime = self.state.currentTime + self.timeAdvance()
  139. outputs = {}
  140. if self.state.send_car_delay == mintime:
  141. v_pref = self.state.next_v_pref
  142. car = Car(self.state.send_car_id, 0, v_pref, self.dv_pos_max, self.dv_neg_max, currentTime)
  143. car.path = self.state.path
  144. #self.poke(self.car_out, car)
  145. outputs[self.car_out] = [car]
  146. elif self.state.send_query_delay == mintime:
  147. query = Query(self.state.send_query_id)
  148. #self.poke(self.Q_send, query)
  149. outputs[self.Q_send] = [query]
  150. return outputs
  151. def timeAdvance(self):
  152. return min(self.state.send_query_delay, self.state.send_car_delay)
  153. def extTransition(self, inputs):
  154. #print("ELAPSED: " + str(self.elapsed))
  155. #print("Got elapsed: " + str(self.elapsed))
  156. self.state.currentTime += self.elapsed
  157. self.state.send_query_delay -= self.elapsed
  158. self.state.send_car_delay -= self.elapsed
  159. queryAcks = inputs.get(self.Q_rack, [])
  160. for queryAck in queryAcks:
  161. if self.state.send_car_id == queryAck.ID and (self.state.sent < self.send_max):
  162. self.state.send_car_delay = queryAck.t_until_dep
  163. if queryAck.t_until_dep < 20000:
  164. self.state.sent += 1
  165. # Generate the next situation
  166. if self.state.sent < self.send_max:
  167. self.state.send_query_delay = self.randomGenerator.uniform(self.IAT_min, self.IAT_max)
  168. #self.state.send_query_id = int(self.randomGenerator.uniform(0, 100000))
  169. self.state.send_query_id += 1000000
  170. return self.state
  171. def preActivityCalculation(self):
  172. return None
  173. def postActivityCalculation(self, _):
  174. return 0 if self.state.send_car_delay == float('inf') else 1
  175. class Residence(Building):
  176. def __init__(self, path, district, name = "Residence", IAT_min = 100, IAT_max = 100, v_pref_min = 15, v_pref_max = 15, dv_pos_max = 15, dv_neg_max = 15):
  177. Building.__init__(self, True, district, path=path, name=name)
  178. class CommercialState(object):
  179. def __init__(self, car):
  180. self.car = car
  181. def __str__(self):
  182. return "CommercialState"
  183. def copy(self):
  184. return CommercialState(self.car)
  185. class Commercial(Building):
  186. def __init__(self, district, name="Commercial"):
  187. Building.__init__(self, False, district, name=name)
  188. self.state = CommercialState(None)
  189. self.toCollector = self.addOutPort(name="toCollector")
  190. def extTransition(self, inputs):
  191. return CommercialState(inputs[self.entry][0])
  192. def intTransition(self):
  193. return CommercialState(None)
  194. def outputFnc(self):
  195. return {self.toCollector: [self.state.car]}
  196. def timeAdvance(self):
  197. if self.state.car is None:
  198. return INFINITY
  199. else:
  200. return 0.0
  201. def preActivityCalculation(self):
  202. return None
  203. def postActivityCalculation(self, _):
  204. return 0
  205. class RoadSegmentState():
  206. def __init__(self):
  207. self.cars_present = []
  208. self.query_buffer = []
  209. self.deny_list = []
  210. self.reserved = False
  211. self.send_query_delay = INFINITY
  212. self.send_query_id = None
  213. self.send_ack_delay = INFINITY
  214. self.send_ack_id = None
  215. self.send_car_delay = INFINITY
  216. self.send_car_id = None
  217. self.last_car = None
  218. def __eq__(self, other):
  219. if not (self.send_query_delay == other.send_query_delay and
  220. self.send_ack_delay == other.send_ack_delay and
  221. self.send_car_delay == other.send_car_delay and
  222. self.send_query_id == other.send_query_id and
  223. self.send_ack_id == other.send_ack_id and
  224. self.send_car_id == other.send_car_id and
  225. self.last_car == other.last_car and
  226. self.reserved == other.reserved):
  227. return False
  228. if self.query_buffer != other.query_buffer:
  229. return False
  230. if len(self.cars_present) != len(other.cars_present):
  231. return False
  232. for c1, c2 in zip(self.cars_present, other.cars_present):
  233. if c1 != c2:
  234. return False
  235. if len(self.deny_list) != len(other.deny_list):
  236. return False
  237. for q1, q2 in zip(self.deny_list, other.deny_list):
  238. if q1 != q2:
  239. return False
  240. return True
  241. def copy(self):
  242. new = RoadSegmentState()
  243. new.cars_present = [c.copy() for c in self.cars_present]
  244. new.query_buffer = list(self.query_buffer)
  245. new.deny_list = [q.copy() for q in self.deny_list]
  246. new.reserved = self.reserved
  247. new.send_query_delay = self.send_query_delay
  248. new.send_query_id = self.send_query_id
  249. new.send_ack_delay = self.send_ack_delay
  250. new.send_ack_id = self.send_ack_id
  251. new.send_car_delay = self.send_car_delay
  252. new.send_car_id = self.send_car_id
  253. new.last_car = self.last_car
  254. return new
  255. def __str__(self):
  256. string = "Road segment: cars_present = ["
  257. for i in self.cars_present:
  258. string += str(i.ID) + ", "
  259. return string + "] , send_query_delay = %.3f, send_ack_delay = %.3f, send_car_delay = %.3f, send_ack_id = %s" % (self.send_query_delay, self.send_ack_delay, self.send_car_delay, self.send_ack_id)
  260. class RoadSegment(AtomicDEVS):
  261. def __init__(self, district, load, l = 100.0, v_max = 18.0, observ_delay = 0.1, name = "RoadSegment"):
  262. AtomicDEVS.__init__(self, name)
  263. # arguments
  264. self.l = float(l)
  265. self.v_max = v_max
  266. self.observ_delay = observ_delay
  267. self.district = district
  268. self.load = load
  269. # in-ports
  270. self.q_rans = self.addInPort(name="q_rans")
  271. self.q_recv = self.addInPort(name="q_recv")
  272. self.car_in = self.addInPort(name="car_in")
  273. self.entries = self.addInPort(name="entries")
  274. self.q_rans_bs = self.addInPort(name="q_rans_bs")
  275. self.q_recv_bs = self.addInPort(name="q_recv_bs")
  276. # compatibility bindings...
  277. self.Q_recv = self.q_recv
  278. self.Q_rack = self.q_rans
  279. # out-ports
  280. self.q_sans = self.addOutPort(name="q_sans")
  281. self.q_send = self.addOutPort(name="q_send")
  282. self.car_out = self.addOutPort(name="car_out")
  283. self.exits = self.addOutPort(name="exits")
  284. self.q_sans_bs = self.addOutPort(name="q_sans_bs")
  285. # compatibility bindings...
  286. self.Q_send = self.q_send
  287. self.Q_sack = self.q_sans
  288. self.state = RoadSegmentState()
  289. def extTransition(self, inputs):
  290. queries = inputs.get(self.Q_recv, [])
  291. queries.extend(inputs.get(self.q_recv_bs, []))
  292. cars = inputs.get(self.car_in, [])
  293. cars.extend(inputs.get(self.entries, []))
  294. acks = inputs.get(self.Q_rack, [])
  295. acks.extend(inputs.get(self.q_rans_bs, []))
  296. self.state.send_query_delay -= self.elapsed
  297. self.state.send_ack_delay -= self.elapsed
  298. self.state.send_car_delay -= self.elapsed
  299. for query in queries:
  300. if (not self.state.reserved) and not (len(self.state.cars_present) > 1 or (len(self.state.cars_present) == 1 and self.state.cars_present[0].v == 0)):
  301. self.state.send_ack_delay = self.observ_delay
  302. self.state.send_ack_id = query.ID
  303. self.state.reserved = True
  304. else:
  305. self.state.query_buffer.append(query.ID)
  306. self.state.deny_list.append(query)
  307. if self.state.send_ack_delay == INFINITY:
  308. self.state.send_ack_delay = self.observ_delay
  309. self.state.send_ack_id = query.ID
  310. self.state.last_car = query.ID
  311. for car in self.state.cars_present:
  312. car.remaining_x -= self.elapsed * car.v
  313. for car in cars:
  314. self.state.last_car = None
  315. car.remaining_x = self.l
  316. self.state.cars_present.append(car)
  317. if len(self.state.cars_present) != 1:
  318. for other_car in self.state.cars_present:
  319. other_car.v = 0
  320. self.state.send_query_delay = INFINITY
  321. self.state.send_ack_delay = INFINITY
  322. self.state.send_car_delay = INFINITY
  323. else:
  324. self.state.send_query_delay = 0
  325. self.state.send_query_id = car.ID
  326. if self.state.cars_present[-1].v == 0:
  327. t_to_dep = INFINITY
  328. else:
  329. t_to_dep = max(0, self.l/self.state.cars_present[-1].v)
  330. self.state.send_car_delay = t_to_dep
  331. self.state.send_car_id = car.ID
  332. for ack in acks:
  333. if (len(self.state.cars_present) == 1) and (ack.ID == self.state.cars_present[0].ID):
  334. car = self.state.cars_present[0]
  335. t_no_col = ack.t_until_dep
  336. v_old = car.v
  337. v_pref = car.v_pref
  338. remaining_x = car.remaining_x
  339. if t_no_col + 1 == t_no_col:
  340. v_new = 0
  341. t_until_dep = INFINITY
  342. else:
  343. v_ideal = remaining_x / max(t_no_col, remaining_x / min(v_pref, self.v_max))
  344. diff = v_ideal - v_old
  345. if diff < 0:
  346. if -diff > car.dv_neg_max:
  347. diff = -car.dv_neg_max
  348. elif diff > 0:
  349. if diff > car.dv_pos_max:
  350. diff = car.dv_pos_max
  351. v_new = v_old + diff
  352. if v_new == 0:
  353. t_until_dep = INFINITY
  354. else:
  355. t_until_dep = car.remaining_x / v_new
  356. car.v = v_new
  357. t_until_dep = max(0, t_until_dep)
  358. if t_until_dep > self.state.send_car_delay and self.state.last_car is not None:
  359. self.state.send_ack_delay = self.observ_delay
  360. self.state.send_ack_id = self.state.last_car
  361. self.state.send_car_delay = t_until_dep
  362. self.state.send_car_id = ack.ID
  363. if t_until_dep == INFINITY:
  364. self.state.send_query_id = ack.ID
  365. else:
  366. self.state.send_query_id = None
  367. self.state.send_query_delay = INFINITY
  368. return self.state
  369. def intTransition(self):
  370. for _ in range(self.load):
  371. pass
  372. mintime = self.mintime()
  373. self.state.send_query_delay -= mintime
  374. self.state.send_ack_delay -= mintime
  375. self.state.send_car_delay -= mintime
  376. if self.state.send_ack_delay == 0:
  377. self.state.send_ack_delay = INFINITY
  378. self.state.send_ack_id = None
  379. elif self.state.send_query_delay == 0:
  380. # Just sent a query, now deny all other queries and wait until the current car has left
  381. self.state.send_query_delay = INFINITY
  382. self.state.send_query_id = None
  383. elif self.state.send_car_delay == 0:
  384. self.state.cars_present = []
  385. self.state.send_car_delay = INFINITY
  386. self.state.send_car_id = None
  387. # A car has left, so we can answer to the first other query we received
  388. if len(self.state.query_buffer) != 0:
  389. self.state.send_ack_delay = self.observ_delay
  390. #print("Setting %s in %s" % (self.state.query_buffer, self.name))
  391. self.state.send_ack_id = self.state.query_buffer.pop()
  392. else:
  393. # No car is waiting for this segment, so 'unreserve' it
  394. self.state.reserved = False
  395. if self.state.send_ack_id == None and len(self.state.deny_list) > 0:
  396. self.state.send_ack_delay = self.observ_delay
  397. #print("Denylist = %s in %s" % (self.state.deny_list, self.name))
  398. self.state.send_ack_id = self.state.deny_list[0].ID
  399. self.state.deny_list = self.state.deny_list[1:]
  400. return self.state
  401. def outputFnc(self):
  402. outputs = {}
  403. mintime = self.mintime()
  404. if self.state.send_ack_delay == mintime:
  405. ackID = self.state.send_ack_id
  406. if len(self.state.cars_present) == 0:
  407. t_until_dep = 0
  408. elif (self.state.cars_present[0].v) == 0:
  409. t_until_dep = INFINITY
  410. else:
  411. t_until_dep = self.l / self.state.cars_present[0].v
  412. ack = QueryAck(ackID, t_until_dep)
  413. outputs[self.Q_sack] = [ack]
  414. outputs[self.q_sans_bs] = [ack]
  415. elif self.state.send_query_delay == mintime:
  416. query = Query(self.state.send_query_id)
  417. if self.state.cars_present[0].path != []:
  418. query.direction = self.state.cars_present[0].path[0]
  419. outputs[self.Q_send] = [query]
  420. elif self.state.send_car_delay == mintime:
  421. car = self.state.cars_present[0]
  422. car.distance_travelled += self.l
  423. if len(car.path) == 0:
  424. outputs[self.exits] = [car]
  425. else:
  426. outputs[self.car_out] = [car]
  427. return outputs
  428. def mintime(self):
  429. return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
  430. def timeAdvance(self):
  431. #return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
  432. delay = min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
  433. # Take care of floating point errors
  434. return max(delay, 0)
  435. def preActivityCalculation(self):
  436. return None
  437. def postActivityCalculation(self, _):
  438. # If a car has collided, no activity is here
  439. return 1 if len(self.state.cars_present) == 1 else 0
  440. class Road(CoupledDEVS):
  441. def __init__(self, district, load, name="Road", segments=5):
  442. CoupledDEVS.__init__(self, name)
  443. self.segment = []
  444. for i in range(segments):
  445. self.segment.append(self.addSubModel(RoadSegment(load=load, district=district, name=(name + "_" + str(i)))))
  446. # in-ports
  447. self.q_rans = self.addInPort(name="q_rans")
  448. self.q_recv = self.addInPort(name="q_recv")
  449. self.car_in = self.addInPort(name="car_in")
  450. self.entries = self.addInPort(name="entries")
  451. self.q_rans_bs = self.addInPort(name="q_rans_bs")
  452. self.q_recv_bs = self.addInPort(name="q_recv_bs")
  453. # out-ports
  454. self.q_sans = self.addOutPort(name="q_sans")
  455. self.q_send = self.addOutPort(name="q_send")
  456. self.car_out = self.addOutPort(name="car_out")
  457. self.exits = self.addOutPort(name="exits")
  458. self.q_sans_bs = self.addOutPort(name="q_sans_bs")
  459. self.connectPorts(self.q_rans, self.segment[-1].q_rans)
  460. self.connectPorts(self.q_recv, self.segment[0].q_recv)
  461. self.connectPorts(self.car_in, self.segment[0].car_in)
  462. self.connectPorts(self.entries, self.segment[0].entries)
  463. self.connectPorts(self.q_rans_bs, self.segment[0].q_rans_bs)
  464. self.connectPorts(self.q_recv_bs, self.segment[0].q_recv_bs)
  465. self.connectPorts(self.segment[0].q_sans, self.q_sans)
  466. self.connectPorts(self.segment[-1].q_send, self.q_send)
  467. self.connectPorts(self.segment[-1].car_out, self.car_out)
  468. self.connectPorts(self.segment[0].exits, self.exits)
  469. self.connectPorts(self.segment[0].q_sans_bs, self.q_sans_bs)
  470. for i in range(segments):
  471. if i == 0:
  472. continue
  473. self.connectPorts(self.segment[i].q_sans, self.segment[i-1].q_rans)
  474. self.connectPorts(self.segment[i-1].q_send, self.segment[i].q_recv)
  475. self.connectPorts(self.segment[i-1].car_out, self.segment[i].car_in)
  476. class IntersectionState():
  477. def __init__(self, switch_signal):
  478. self.send_query = []
  479. self.send_ack = []
  480. self.send_car = []
  481. self.queued_queries = []
  482. self.id_locations = [None, None, None, None]
  483. self.block = vertical
  484. self.switch_signal = switch_signal
  485. self.ackDir = {}
  486. def __str__(self):
  487. return "ISECT blocking " + str(self.block)
  488. return "Intersection: send_query = " + str(self.send_query) + ", send_ack = " + str(self.send_ack) + ", send_car = " + str(self.send_car) + ", block = " + str(self.block)
  489. def copy(self):
  490. new = IntersectionState(self.switch_signal)
  491. new.send_query = [q.copy() for q in self.send_query]
  492. new.send_ack = [a.copy() for a in self.send_ack]
  493. new.send_car = [c.copy() for c in self.send_car]
  494. new.queued_queries = [q.copy() for q in self.queued_queries]
  495. new.id_locations = list(self.id_locations)
  496. new.block = self.block
  497. new.switch_signal = self.switch_signal
  498. new.ackDir = dict(self.ackDir)
  499. return new
  500. class Intersection(AtomicDEVS):
  501. def __init__(self, district, name="Intersection", switch_signal = 30):
  502. AtomicDEVS.__init__(self, name=name)
  503. self.state = IntersectionState(switch_signal)
  504. self.switch_signal_delay = switch_signal
  505. self.district = district
  506. self.q_send = []
  507. self.q_send.append(self.addOutPort(name="q_send_to_n"))
  508. self.q_send.append(self.addOutPort(name="q_send_to_e"))
  509. self.q_send.append(self.addOutPort(name="q_send_to_s"))
  510. self.q_send.append(self.addOutPort(name="q_send_to_w"))
  511. self.q_rans = []
  512. self.q_rans.append(self.addInPort(name="q_rans_from_n"))
  513. self.q_rans.append(self.addInPort(name="q_rans_from_e"))
  514. self.q_rans.append(self.addInPort(name="q_rans_from_s"))
  515. self.q_rans.append(self.addInPort(name="q_rans_from_w"))
  516. self.q_recv = []
  517. self.q_recv.append(self.addInPort(name="q_recv_from_n"))
  518. self.q_recv.append(self.addInPort(name="q_recv_from_e"))
  519. self.q_recv.append(self.addInPort(name="q_recv_from_s"))
  520. self.q_recv.append(self.addInPort(name="q_recv_from_w"))
  521. self.q_sans = []
  522. self.q_sans.append(self.addOutPort(name="q_sans_to_n"))
  523. self.q_sans.append(self.addOutPort(name="q_sans_to_e"))
  524. self.q_sans.append(self.addOutPort(name="q_sans_to_s"))
  525. self.q_sans.append(self.addOutPort(name="q_sans_to_w"))
  526. self.car_in = []
  527. self.car_in.append(self.addInPort(name="car_in_from_n"))
  528. self.car_in.append(self.addInPort(name="car_in_from_e"))
  529. self.car_in.append(self.addInPort(name="car_in_from_s"))
  530. self.car_in.append(self.addInPort(name="car_in_from_w"))
  531. self.car_out = []
  532. self.car_out.append(self.addOutPort(name="car_out_to_n"))
  533. self.car_out.append(self.addOutPort(name="car_out_to_e"))
  534. self.car_out.append(self.addOutPort(name="car_out_to_s"))
  535. self.car_out.append(self.addOutPort(name="car_out_to_w"))
  536. def intTransition(self):
  537. self.state.switch_signal -= self.timeAdvance()
  538. if self.state.switch_signal <= 1e-6:
  539. # We switched our traffic lights
  540. self.state.switch_signal = self.switch_signal_delay
  541. self.state.queued_queries = []
  542. self.state.block = vertical if self.state.block == horizontal else horizontal
  543. for loc, car_id in enumerate(self.state.id_locations):
  544. # Notify all cars that got 'green' that they should not continue
  545. if car_id is None:
  546. continue
  547. try:
  548. if str(loc) in self.state.block:
  549. query = Query(car_id)
  550. query.direction = int_to_dir[self.state.ackDir[car_id]]
  551. self.state.queued_queries.append(query)
  552. except KeyError:
  553. pass
  554. self.state.send_car = []
  555. self.state.send_query = []
  556. self.state.send_ack = []
  557. return self.state
  558. def extTransition(self, inputs):
  559. # Simple forwarding of all messages
  560. # Unless the direction in which it is going is blocked
  561. self.state.switch_signal -= self.elapsed
  562. for direction in range(4):
  563. blocked = str(direction) in self.state.block
  564. for car in inputs.get(self.car_in[direction], []):
  565. self.state.send_car.append(car)
  566. # Got a car, so remove its ID location entry
  567. try:
  568. del self.state.ackDir[car.ID]
  569. self.state.id_locations[self.state.id_locations.index(car.ID)] = None
  570. except (KeyError, ValueError):
  571. pass
  572. self.state.queued_queries = [query for query in self.state.queued_queries if query.ID != car.ID]
  573. for query in inputs.get(self.q_recv[direction], []):
  574. self.state.id_locations[direction] = query.ID
  575. self.state.ackDir[query.ID] = dir_to_int[query.direction]
  576. if blocked:
  577. self.state.send_ack.append(QueryAck(query.ID, INFINITY))
  578. self.state.queued_queries.append(query)
  579. else:
  580. self.state.send_query.append(query)
  581. for ack in inputs.get(self.q_rans[direction], []):
  582. self.state.ackDir[ack.ID] = direction
  583. if (ack.t_until_dep > self.state.switch_signal) or ((ack.ID in self.state.id_locations) and (str(self.state.id_locations.index(ack.ID)) in self.state.block)):
  584. try:
  585. self.state.id_locations.index(ack.ID)
  586. t_until_dep = INFINITY
  587. nquery = Query(ack.ID)
  588. nquery.direction = int_to_dir[direction]
  589. self.state.queued_queries.append(nquery)
  590. except ValueError:
  591. continue
  592. else:
  593. t_until_dep = ack.t_until_dep
  594. self.state.send_ack.append(QueryAck(ack.ID, t_until_dep))
  595. return self.state
  596. def outputFnc(self):
  597. # Can simply overwrite, as multiple calls to the same destination is impossible
  598. toSend = {}
  599. new_block = vertical if self.state.block == horizontal else horizontal
  600. if self.state.switch_signal == self.timeAdvance():
  601. # We switch our traffic lights
  602. # Resend all queries for those that are waiting
  603. for query in self.state.queued_queries:
  604. if str(self.state.id_locations.index(query.ID)) not in new_block:
  605. toSend[self.q_send[dir_to_int[query.direction]]] = [query]
  606. for loc, car_id in enumerate(self.state.id_locations):
  607. # Notify all cars that got 'green' that they should not continue
  608. if car_id is None:
  609. continue
  610. if str(loc) in new_block:
  611. toSend[self.q_sans[loc]] = [QueryAck(car_id, INFINITY)]
  612. else:
  613. try:
  614. query = Query(car_id)
  615. query.direction = int_to_dir[self.state.ackDir[car_id]]
  616. toSend[self.q_send[self.state.ackDir[car_id]]] = [query]
  617. except KeyError:
  618. pass
  619. # We might have some messages to forward too
  620. for car in self.state.send_car:
  621. dest = car.path.pop(0)
  622. toSend[self.car_out[dir_to_int[dest]]] = [car]
  623. for query in self.state.send_query:
  624. toSend[self.q_send[dir_to_int[query.direction]]] = [query]
  625. for ack in self.state.send_ack:
  626. # Broadcast for now
  627. try:
  628. toSend[self.q_sans[self.state.id_locations.index(ack.ID)]] = [ack]
  629. except ValueError:
  630. pass
  631. return toSend
  632. def timeAdvance(self):
  633. if len(self.state.send_car) + len(self.state.send_query) + len(self.state.send_ack) > 0:
  634. return 0.0
  635. else:
  636. return max(self.state.switch_signal, 0.0)
  637. def preActivityCalculation(self):
  638. return None
  639. def postActivityCalculation(self, _):
  640. return len(self.state.send_car)
  641. class CollectorState(object):
  642. def __init__(self):
  643. self.cars = []
  644. def copy(self):
  645. new = CollectorState()
  646. new.cars = list(self.cars)
  647. return new
  648. def __str__(self):
  649. ## Print your statistics here!
  650. s = "All cars collected:"
  651. for car in self.cars:
  652. s += "\n\t\t\t%s" % car
  653. return s
  654. class Collector(AtomicDEVS):
  655. def __init__(self):
  656. AtomicDEVS.__init__(self, "Collector")
  657. self.car_in = self.addInPort("car_in")
  658. self.state = CollectorState()
  659. self.district = 0
  660. def extTransition(self, inputs):
  661. self.state.cars.extend(inputs[self.car_in])
  662. return self.state
  663. def preActivityCalculation(self):
  664. return None
  665. def postActivityCalculation(self, _):
  666. return 0