trafficModels.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  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. class Residence(Building):
  172. 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):
  173. Building.__init__(self, True, district, path=path, name=name)
  174. class CommercialState(object):
  175. def __init__(self, car):
  176. self.car = car
  177. def __str__(self):
  178. return "CommercialState"
  179. def copy(self):
  180. return CommercialState(self.car)
  181. class Commercial(Building):
  182. def __init__(self, district, name="Commercial"):
  183. Building.__init__(self, False, district, name=name)
  184. self.state = CommercialState(None)
  185. self.toCollector = self.addOutPort(name="toCollector")
  186. def extTransition(self, inputs):
  187. return CommercialState(inputs[self.entry][0])
  188. def intTransition(self):
  189. return CommercialState(None)
  190. def outputFnc(self):
  191. return {self.toCollector: [self.state.car]}
  192. def timeAdvance(self):
  193. if self.state.car is None:
  194. return INFINITY
  195. else:
  196. return 0.0
  197. class RoadSegmentState():
  198. def __init__(self):
  199. self.cars_present = []
  200. self.query_buffer = []
  201. self.deny_list = []
  202. self.reserved = False
  203. self.send_query_delay = INFINITY
  204. self.send_query_id = None
  205. self.send_ack_delay = INFINITY
  206. self.send_ack_id = None
  207. self.send_car_delay = INFINITY
  208. self.send_car_id = None
  209. self.last_car = None
  210. def __eq__(self, other):
  211. if self.query_buffer != other.query_buffer:
  212. return False
  213. if not (self.send_query_delay == other.send_query_delay and
  214. self.send_ack_delay == other.send_ack_delay and
  215. self.send_car_delay == other.send_car_delay and
  216. self.send_query_id == other.send_query_id and
  217. self.send_ack_id == other.send_ack_id and
  218. self.send_car_id == other.send_car_id):
  219. return False
  220. if self.reserved != other.reserved:
  221. return False
  222. if len(self.cars_present) != len(other.cars_present):
  223. return False
  224. for c1, c2 in zip(self.cars_present, other.cars_present):
  225. if c1 != c2:
  226. return False
  227. if self.last_car != other.last_car:
  228. return False
  229. if len(self.deny_list) != len(other.deny_list):
  230. return False
  231. for q1, q2 in zip(self.deny_list, other.deny_list):
  232. if q1 != q2:
  233. return False
  234. return True
  235. def copy(self):
  236. new = RoadSegmentState()
  237. new.cars_present = [c.copy() for c in self.cars_present]
  238. new.deny_list = [q.copy() for q in self.deny_list]
  239. new.query_buffer = list(self.query_buffer)
  240. new.reserved = self.reserved
  241. new.send_query_delay = self.send_query_delay
  242. new.send_query_id = self.send_query_id
  243. new.send_ack_delay = self.send_ack_delay
  244. new.send_ack_id = self.send_ack_id
  245. new.send_car_delay = self.send_car_delay
  246. new.send_car_id = self.send_car_id
  247. new.last_car = self.last_car
  248. return new
  249. def __str__(self):
  250. string = "Road segment: cars_present = ["
  251. for i in self.cars_present:
  252. string += str(i.ID) + ", "
  253. 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)
  254. class RoadSegment(AtomicDEVS):
  255. def __init__(self, district, load, l = 100.0, v_max = 18.0, observ_delay = 0.1, name = "RoadSegment"):
  256. AtomicDEVS.__init__(self, name)
  257. # arguments
  258. self.l = float(l)
  259. self.v_max = v_max
  260. self.observ_delay = observ_delay
  261. self.district = district
  262. self.load = load
  263. # in-ports
  264. self.q_rans = self.addInPort(name="q_rans")
  265. self.q_recv = self.addInPort(name="q_recv")
  266. self.car_in = self.addInPort(name="car_in")
  267. self.entries = self.addInPort(name="entries")
  268. self.q_rans_bs = self.addInPort(name="q_rans_bs")
  269. self.q_recv_bs = self.addInPort(name="q_recv_bs")
  270. # compatibility bindings...
  271. self.Q_recv = self.q_recv
  272. self.Q_rack = self.q_rans
  273. # out-ports
  274. self.q_sans = self.addOutPort(name="q_sans")
  275. self.q_send = self.addOutPort(name="q_send")
  276. self.car_out = self.addOutPort(name="car_out")
  277. self.exits = self.addOutPort(name="exits")
  278. self.q_sans_bs = self.addOutPort(name="q_sans_bs")
  279. # compatibility bindings...
  280. self.Q_send = self.q_send
  281. self.Q_sack = self.q_sans
  282. self.state = RoadSegmentState()
  283. def extTransition(self, inputs):
  284. queries = inputs.get(self.Q_recv, [])
  285. queries.extend(inputs.get(self.q_recv_bs, []))
  286. cars = inputs.get(self.car_in, [])
  287. cars.extend(inputs.get(self.entries, []))
  288. acks = inputs.get(self.Q_rack, [])
  289. acks.extend(inputs.get(self.q_rans_bs, []))
  290. self.state.send_query_delay -= self.elapsed
  291. self.state.send_ack_delay -= self.elapsed
  292. self.state.send_car_delay -= self.elapsed
  293. for query in queries:
  294. 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)):
  295. self.state.send_ack_delay = self.observ_delay
  296. self.state.send_ack_id = query.ID
  297. self.state.reserved = True
  298. else:
  299. self.state.query_buffer.append(query.ID)
  300. self.state.deny_list.append(query)
  301. if self.state.send_ack_delay == INFINITY:
  302. self.state.send_ack_delay = self.observ_delay
  303. self.state.send_ack_id = query.ID
  304. self.state.last_car = query.ID
  305. for car in self.state.cars_present:
  306. car.remaining_x -= self.elapsed * car.v
  307. for car in cars:
  308. self.state.last_car = None
  309. car.remaining_x = self.l
  310. self.state.cars_present.append(car)
  311. if len(self.state.cars_present) != 1:
  312. for other_car in self.state.cars_present:
  313. other_car.v = 0
  314. self.state.send_query_delay = INFINITY
  315. self.state.send_ack_delay = INFINITY
  316. self.state.send_car_delay = INFINITY
  317. else:
  318. self.state.send_query_delay = 0
  319. self.state.send_query_id = car.ID
  320. if self.state.cars_present[-1].v == 0:
  321. t_to_dep = INFINITY
  322. else:
  323. t_to_dep = max(0, self.l/self.state.cars_present[-1].v)
  324. self.state.send_car_delay = t_to_dep
  325. self.state.send_car_id = car.ID
  326. for ack in acks:
  327. if (len(self.state.cars_present) == 1) and (ack.ID == self.state.cars_present[0].ID):
  328. car = self.state.cars_present[0]
  329. t_no_col = ack.t_until_dep
  330. v_old = car.v
  331. v_pref = car.v_pref
  332. remaining_x = car.remaining_x
  333. if t_no_col + 1 == t_no_col:
  334. v_new = 0
  335. t_until_dep = INFINITY
  336. else:
  337. v_ideal = remaining_x / max(t_no_col, remaining_x / min(v_pref, self.v_max))
  338. diff = v_ideal - v_old
  339. if diff < 0:
  340. if -diff > car.dv_neg_max:
  341. diff = -car.dv_neg_max
  342. elif diff > 0:
  343. if diff > car.dv_pos_max:
  344. diff = car.dv_pos_max
  345. v_new = v_old + diff
  346. if v_new == 0:
  347. t_until_dep = INFINITY
  348. else:
  349. t_until_dep = car.remaining_x / v_new
  350. car.v = v_new
  351. t_until_dep = max(0, t_until_dep)
  352. if t_until_dep > self.state.send_car_delay and self.state.last_car is not None:
  353. self.state.send_ack_delay = self.observ_delay
  354. self.state.send_ack_id = self.state.last_car
  355. self.state.send_car_delay = t_until_dep
  356. self.state.send_car_id = ack.ID
  357. if t_until_dep == INFINITY:
  358. self.state.send_query_id = ack.ID
  359. else:
  360. self.state.send_query_id = None
  361. self.state.send_query_delay = INFINITY
  362. return self.state
  363. def intTransition(self):
  364. for _ in range(self.load):
  365. pass
  366. mintime = self.mintime()
  367. self.state.send_query_delay -= mintime
  368. self.state.send_ack_delay -= mintime
  369. self.state.send_car_delay -= mintime
  370. if self.state.send_ack_delay == 0:
  371. self.state.send_ack_delay = INFINITY
  372. self.state.send_ack_id = None
  373. elif self.state.send_query_delay == 0:
  374. # Just sent a query, now deny all other queries and wait until the current car has left
  375. self.state.send_query_delay = INFINITY
  376. self.state.send_query_id = None
  377. elif self.state.send_car_delay == 0:
  378. self.state.cars_present = []
  379. self.state.send_car_delay = INFINITY
  380. self.state.send_car_id = None
  381. # A car has left, so we can answer to the first other query we received
  382. if len(self.state.query_buffer) != 0:
  383. self.state.send_ack_delay = self.observ_delay
  384. #print("Setting %s in %s" % (self.state.query_buffer, self.name))
  385. self.state.send_ack_id = self.state.query_buffer.pop()
  386. else:
  387. # No car is waiting for this segment, so 'unreserve' it
  388. self.state.reserved = False
  389. if self.state.send_ack_id == None and len(self.state.deny_list) > 0:
  390. self.state.send_ack_delay = self.observ_delay
  391. #print("Denylist = %s in %s" % (self.state.deny_list, self.name))
  392. self.state.send_ack_id = self.state.deny_list[0].ID
  393. self.state.deny_list = self.state.deny_list[1:]
  394. return self.state
  395. def outputFnc(self):
  396. outputs = {}
  397. mintime = self.mintime()
  398. if self.state.send_ack_delay == mintime:
  399. ackID = self.state.send_ack_id
  400. if len(self.state.cars_present) == 0:
  401. t_until_dep = 0
  402. elif (self.state.cars_present[0].v) == 0:
  403. t_until_dep = INFINITY
  404. else:
  405. t_until_dep = self.l / self.state.cars_present[0].v
  406. ack = QueryAck(ackID, t_until_dep)
  407. outputs[self.Q_sack] = [ack]
  408. outputs[self.q_sans_bs] = [ack]
  409. elif self.state.send_query_delay == mintime:
  410. query = Query(self.state.send_query_id)
  411. if self.state.cars_present[0].path != []:
  412. query.direction = self.state.cars_present[0].path[0]
  413. outputs[self.Q_send] = [query]
  414. elif self.state.send_car_delay == mintime:
  415. car = self.state.cars_present[0]
  416. car.distance_travelled += self.l
  417. if len(car.path) == 0:
  418. outputs[self.exits] = [car]
  419. else:
  420. outputs[self.car_out] = [car]
  421. return outputs
  422. def mintime(self):
  423. return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
  424. def timeAdvance(self):
  425. #return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
  426. delay = min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
  427. # Take care of floating point errors
  428. return max(delay, 0)
  429. class Road(CoupledDEVS):
  430. def __init__(self, district, load, name="Road", segments=5):
  431. CoupledDEVS.__init__(self, name)
  432. self.segment = []
  433. for i in range(segments):
  434. self.segment.append(self.addSubModel(RoadSegment(load=load, district=district, name=(name + "_" + str(i)))))
  435. # in-ports
  436. self.q_rans = self.addInPort(name="q_rans")
  437. self.q_recv = self.addInPort(name="q_recv")
  438. self.car_in = self.addInPort(name="car_in")
  439. self.entries = self.addInPort(name="entries")
  440. self.q_rans_bs = self.addInPort(name="q_rans_bs")
  441. self.q_recv_bs = self.addInPort(name="q_recv_bs")
  442. # out-ports
  443. self.q_sans = self.addOutPort(name="q_sans")
  444. self.q_send = self.addOutPort(name="q_send")
  445. self.car_out = self.addOutPort(name="car_out")
  446. self.exits = self.addOutPort(name="exits")
  447. self.q_sans_bs = self.addOutPort(name="q_sans_bs")
  448. self.connectPorts(self.q_rans, self.segment[-1].q_rans)
  449. self.connectPorts(self.q_recv, self.segment[0].q_recv)
  450. self.connectPorts(self.car_in, self.segment[0].car_in)
  451. self.connectPorts(self.entries, self.segment[0].entries)
  452. self.connectPorts(self.q_rans_bs, self.segment[0].q_rans_bs)
  453. self.connectPorts(self.q_recv_bs, self.segment[0].q_recv_bs)
  454. self.connectPorts(self.segment[0].q_sans, self.q_sans)
  455. self.connectPorts(self.segment[-1].q_send, self.q_send)
  456. self.connectPorts(self.segment[-1].car_out, self.car_out)
  457. self.connectPorts(self.segment[0].exits, self.exits)
  458. self.connectPorts(self.segment[0].q_sans_bs, self.q_sans_bs)
  459. for i in range(segments):
  460. if i == 0:
  461. continue
  462. self.connectPorts(self.segment[i].q_sans, self.segment[i-1].q_rans)
  463. self.connectPorts(self.segment[i-1].q_send, self.segment[i].q_recv)
  464. self.connectPorts(self.segment[i-1].car_out, self.segment[i].car_in)
  465. class IntersectionState():
  466. def __init__(self, switch_signal):
  467. self.send_query = []
  468. self.send_ack = []
  469. self.send_car = []
  470. self.queued_queries = []
  471. self.id_locations = [None, None, None, None]
  472. self.block = vertical
  473. self.switch_signal = switch_signal
  474. self.ackDir = {}
  475. def __str__(self):
  476. return "ISECT blocking " + str(self.block)
  477. return "Intersection: send_query = " + str(self.send_query) + ", send_ack = " + str(self.send_ack) + ", send_car = " + str(self.send_car) + ", block = " + str(self.block)
  478. def copy(self):
  479. new = IntersectionState(self.switch_signal)
  480. new.send_query = [q.copy() for q in self.send_query]
  481. new.send_ack = [a.copy() for a in self.send_ack]
  482. new.send_car = [c.copy() for c in self.send_car]
  483. new.queued_queries = [q.copy() for q in self.queued_queries]
  484. new.id_locations = list(self.id_locations)
  485. new.block = self.block
  486. new.switch_signal = self.switch_signal
  487. new.ackDir = dict(self.ackDir)
  488. return new
  489. class Intersection(AtomicDEVS):
  490. def __init__(self, district, name="Intersection", switch_signal = 30):
  491. AtomicDEVS.__init__(self, name=name)
  492. self.state = IntersectionState(switch_signal)
  493. self.switch_signal_delay = switch_signal
  494. self.district = district
  495. self.q_send = []
  496. self.q_send.append(self.addOutPort(name="q_send_to_n"))
  497. self.q_send.append(self.addOutPort(name="q_send_to_e"))
  498. self.q_send.append(self.addOutPort(name="q_send_to_s"))
  499. self.q_send.append(self.addOutPort(name="q_send_to_w"))
  500. self.q_rans = []
  501. self.q_rans.append(self.addInPort(name="q_rans_from_n"))
  502. self.q_rans.append(self.addInPort(name="q_rans_from_e"))
  503. self.q_rans.append(self.addInPort(name="q_rans_from_s"))
  504. self.q_rans.append(self.addInPort(name="q_rans_from_w"))
  505. self.q_recv = []
  506. self.q_recv.append(self.addInPort(name="q_recv_from_n"))
  507. self.q_recv.append(self.addInPort(name="q_recv_from_e"))
  508. self.q_recv.append(self.addInPort(name="q_recv_from_s"))
  509. self.q_recv.append(self.addInPort(name="q_recv_from_w"))
  510. self.q_sans = []
  511. self.q_sans.append(self.addOutPort(name="q_sans_to_n"))
  512. self.q_sans.append(self.addOutPort(name="q_sans_to_e"))
  513. self.q_sans.append(self.addOutPort(name="q_sans_to_s"))
  514. self.q_sans.append(self.addOutPort(name="q_sans_to_w"))
  515. self.car_in = []
  516. self.car_in.append(self.addInPort(name="car_in_from_n"))
  517. self.car_in.append(self.addInPort(name="car_in_from_e"))
  518. self.car_in.append(self.addInPort(name="car_in_from_s"))
  519. self.car_in.append(self.addInPort(name="car_in_from_w"))
  520. self.car_out = []
  521. self.car_out.append(self.addOutPort(name="car_out_to_n"))
  522. self.car_out.append(self.addOutPort(name="car_out_to_e"))
  523. self.car_out.append(self.addOutPort(name="car_out_to_s"))
  524. self.car_out.append(self.addOutPort(name="car_out_to_w"))
  525. def intTransition(self):
  526. self.state.switch_signal -= self.timeAdvance()
  527. if self.state.switch_signal <= 1e-6:
  528. # We switched our traffic lights
  529. self.state.switch_signal = self.switch_signal_delay
  530. self.state.queued_queries = []
  531. self.state.block = vertical if self.state.block == horizontal else horizontal
  532. for loc, car_id in enumerate(self.state.id_locations):
  533. # Notify all cars that got 'green' that they should not continue
  534. if car_id is None:
  535. continue
  536. try:
  537. if str(loc) in self.state.block:
  538. query = Query(car_id)
  539. query.direction = int_to_dir[self.state.ackDir[car_id]]
  540. self.state.queued_queries.append(query)
  541. except KeyError:
  542. pass
  543. self.state.send_car = []
  544. self.state.send_query = []
  545. self.state.send_ack = []
  546. return self.state
  547. def extTransition(self, inputs):
  548. # Simple forwarding of all messages
  549. # Unless the direction in which it is going is blocked
  550. self.state.switch_signal -= self.elapsed
  551. for direction in range(4):
  552. blocked = str(direction) in self.state.block
  553. for car in inputs.get(self.car_in[direction], []):
  554. self.state.send_car.append(car)
  555. # Got a car, so remove its ID location entry
  556. try:
  557. del self.state.ackDir[car.ID]
  558. self.state.id_locations[self.state.id_locations.index(car.ID)] = None
  559. except (KeyError, ValueError):
  560. pass
  561. self.state.queued_queries = [query for query in self.state.queued_queries if query.ID != car.ID]
  562. for query in inputs.get(self.q_recv[direction], []):
  563. self.state.id_locations[direction] = query.ID
  564. self.state.ackDir[query.ID] = dir_to_int[query.direction]
  565. if blocked:
  566. self.state.send_ack.append(QueryAck(query.ID, INFINITY))
  567. self.state.queued_queries.append(query)
  568. else:
  569. self.state.send_query.append(query)
  570. for ack in inputs.get(self.q_rans[direction], []):
  571. self.state.ackDir[ack.ID] = direction
  572. 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)):
  573. try:
  574. self.state.id_locations.index(ack.ID)
  575. t_until_dep = INFINITY
  576. nquery = Query(ack.ID)
  577. nquery.direction = int_to_dir[direction]
  578. self.state.queued_queries.append(nquery)
  579. except ValueError:
  580. continue
  581. else:
  582. t_until_dep = ack.t_until_dep
  583. self.state.send_ack.append(QueryAck(ack.ID, t_until_dep))
  584. return self.state
  585. def outputFnc(self):
  586. # Can simply overwrite, as multiple calls to the same destination is impossible
  587. toSend = {}
  588. new_block = vertical if self.state.block == horizontal else horizontal
  589. if self.state.switch_signal == self.timeAdvance():
  590. # We switch our traffic lights
  591. # Resend all queries for those that are waiting
  592. for query in self.state.queued_queries:
  593. if str(self.state.id_locations.index(query.ID)) not in new_block:
  594. toSend[self.q_send[dir_to_int[query.direction]]] = [query]
  595. for loc, car_id in enumerate(self.state.id_locations):
  596. # Notify all cars that got 'green' that they should not continue
  597. if car_id is None:
  598. continue
  599. if str(loc) in new_block:
  600. toSend[self.q_sans[loc]] = [QueryAck(car_id, INFINITY)]
  601. else:
  602. try:
  603. query = Query(car_id)
  604. query.direction = int_to_dir[self.state.ackDir[car_id]]
  605. toSend[self.q_send[self.state.ackDir[car_id]]] = [query]
  606. except KeyError:
  607. pass
  608. # We might have some messages to forward too
  609. for car in self.state.send_car:
  610. dest = car.path.pop(0)
  611. toSend[self.car_out[dir_to_int[dest]]] = [car]
  612. for query in self.state.send_query:
  613. toSend[self.q_send[dir_to_int[query.direction]]] = [query]
  614. for ack in self.state.send_ack:
  615. # Broadcast for now
  616. try:
  617. toSend[self.q_sans[self.state.id_locations.index(ack.ID)]] = [ack]
  618. except ValueError:
  619. pass
  620. return toSend
  621. def timeAdvance(self):
  622. if len(self.state.send_car) + len(self.state.send_query) + len(self.state.send_ack) > 0:
  623. return 0.0
  624. else:
  625. return max(self.state.switch_signal, 0.0)
  626. class CollectorState(object):
  627. def __init__(self):
  628. self.cars = []
  629. def copy(self):
  630. new = CollectorState()
  631. new.cars = list(self.cars)
  632. return new
  633. def __str__(self):
  634. ## Print your statistics here!
  635. s = "All cars collected:"
  636. for car in self.cars:
  637. s += "\n\t\t\t%s" % car
  638. return s
  639. class Collector(AtomicDEVS):
  640. def __init__(self):
  641. AtomicDEVS.__init__(self, "Collector")
  642. self.car_in = self.addInPort("car_in")
  643. self.state = CollectorState()
  644. self.district = 0
  645. def extTransition(self, inputs):
  646. self.state.cars.extend(inputs[self.car_in])
  647. return self.state