Initial commit
This commit is contained in:
commit
66a6860316
407 changed files with 1254365 additions and 0 deletions
|
|
@ -0,0 +1,61 @@
|
|||
from collections import defaultdict
|
||||
|
||||
class CityRelocator(object):
|
||||
def __init__(self):
|
||||
self.server = None
|
||||
self.kernels = 0
|
||||
self.model_ids = []
|
||||
|
||||
def setController(self, controller):
|
||||
self.kernels = controller.kernels
|
||||
self.server = controller.server
|
||||
self.model_ids = controller.model_ids
|
||||
self.districts = defaultdict(list)
|
||||
for m in controller.total_model.componentSet:
|
||||
self.districts[m.district].append(m)
|
||||
self.districts = [self.districts[i] for i in range(len(self.districts))]
|
||||
|
||||
def getRelocations(self, GVT, activities, horizon):
|
||||
# Ignore activities variable
|
||||
# Fetch all models and their activity
|
||||
if GVT < 100.0:
|
||||
return {}
|
||||
previous_district_allocation = [district[0].location for district in self.districts]
|
||||
relocate = {}
|
||||
district_activities = defaultdict(float)
|
||||
for i in range(self.kernels):
|
||||
for model_id, activity in self.server.getProxy(i).getCompleteActivity().items():
|
||||
district_activities[self.model_ids[model_id].district] += activity
|
||||
district_activities = [district_activities[i] for i in range(len(district_activities))]
|
||||
print("All loads: " + str(district_activities))
|
||||
avg_activity_per_node = float(sum(district_activities)) / self.kernels
|
||||
print("Avg: " + str(avg_activity_per_node))
|
||||
running_activity = 0.0
|
||||
district_allocation = []
|
||||
to_allocate = []
|
||||
for district, activity in enumerate(district_activities):
|
||||
if abs(running_activity - avg_activity_per_node) < abs(running_activity - avg_activity_per_node + activity):
|
||||
# Enough activity for this node, so put all these districts there
|
||||
district_allocation.append(to_allocate)
|
||||
running_activity = activity
|
||||
to_allocate = [district]
|
||||
else:
|
||||
running_activity += activity
|
||||
to_allocate.append(district)
|
||||
if len(district_allocation) < self.kernels:
|
||||
# Still have to add the last node
|
||||
district_allocation.append(to_allocate)
|
||||
else:
|
||||
district_allocation[-1].extend(to_allocate)
|
||||
print("Migrating to %s" % district_allocation)
|
||||
for node, districts in enumerate(district_allocation):
|
||||
for district in districts:
|
||||
if previous_district_allocation[district] == node or (previous_district_allocation[district] < node and GVT > horizon):
|
||||
continue
|
||||
print("Moving " + str(district) + " to " + str(node))
|
||||
for model in self.districts[district]:
|
||||
relocate[model.model_id] = node
|
||||
return relocate
|
||||
|
||||
def useLastStateOnly(self):
|
||||
return False
|
||||
|
|
@ -0,0 +1,741 @@
|
|||
import sys
|
||||
sys.path.append("../../../src/")
|
||||
from infinity import *
|
||||
from DEVS import *
|
||||
import random
|
||||
|
||||
north = 0
|
||||
east = 1
|
||||
south = 2
|
||||
west = 3
|
||||
vertical = "02"
|
||||
horizontal = "13"
|
||||
dir_to_int = {'n': north, 'e': east, 's': south, 'w': west}
|
||||
int_to_dir = {north: 'n', east: 'e', south: 's', west: 'w'}
|
||||
|
||||
class Car:
|
||||
def __init__(self, ID, v, v_pref, dv_pos_max, dv_neg_max, departure_time):
|
||||
self.ID = ID
|
||||
self.v_pref = v_pref
|
||||
self.dv_pos_max = dv_pos_max
|
||||
self.dv_neg_max = dv_neg_max
|
||||
self.departure_time = departure_time
|
||||
self.distance_travelled = 0
|
||||
self.remaining_x = 0
|
||||
self.v = v
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and
|
||||
self.v_pref == other.v_pref and
|
||||
self.dv_pos_max == other.dv_pos_max and
|
||||
self.dv_neg_max == other.dv_neg_max and
|
||||
self.departure_time == other.departure_time and
|
||||
self.distance_travelled == other.distance_travelled and
|
||||
self.remaining_x == other.remaining_x and
|
||||
self.v == other.v)
|
||||
|
||||
def __str__(self):
|
||||
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)
|
||||
|
||||
def copy(self):
|
||||
car = Car(self.ID, self.v, self.v_pref, self.dv_pos_max, self.dv_neg_max, self.departure_time)
|
||||
car.distance_travelled = self.distance_travelled
|
||||
car.remaining_x = self.remaining_x
|
||||
car.path = list(self.path)
|
||||
return car
|
||||
|
||||
class Query:
|
||||
def __init__(self, ID):
|
||||
self.ID = ID
|
||||
self.direction = ''
|
||||
|
||||
def __str__(self):
|
||||
return "Query: ID = " + str(self.ID)
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and self.direction == other.direction)
|
||||
|
||||
def copy(self):
|
||||
query = Query(self.ID)
|
||||
query.direction = self.direction
|
||||
return query
|
||||
|
||||
class QueryAck:
|
||||
def __init__(self, ID, t_until_dep):
|
||||
self.ID = ID
|
||||
self.t_until_dep = t_until_dep
|
||||
|
||||
def __str__(self):
|
||||
return "Query Ack: ID = " + str(self.ID) + ", t_until_dep = %.3f" % self.t_until_dep
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and self.t_until_dep == other.t_until_dep)
|
||||
|
||||
def copy(self):
|
||||
return QueryAck(self.ID, self.t_until_dep)
|
||||
|
||||
class BuildingState:
|
||||
def __init__(self, IAT_min, IAT_max, path, name):
|
||||
self.currentTime = 0
|
||||
from randomGenerator import RandomGenerator
|
||||
seed = random.random()
|
||||
self.randomGenerator = RandomGenerator(seed)
|
||||
self.send_query_delay = self.randomGenerator.uniform(IAT_min, IAT_max)
|
||||
|
||||
self.send_car_delay = INFINITY
|
||||
self.path = path
|
||||
if path == []:
|
||||
self.send_query_delay = INFINITY
|
||||
|
||||
self.name = name
|
||||
self.send_query_id = int(name.split("_", 1)[1].split("_")[0]) * 1000 + int(name.split("_", 1)[1].split("_")[1])
|
||||
self.send_car_id = self.send_query_id
|
||||
self.next_v_pref = 0
|
||||
self.sent = 0
|
||||
|
||||
def copy(self):
|
||||
new = BuildingState(0, 0, list(self.path), self.name)
|
||||
new.currentTime = self.currentTime
|
||||
new.send_query_delay = self.send_query_delay
|
||||
new.send_car_delay = self.send_car_delay
|
||||
new.send_query_id = self.send_query_id
|
||||
new.send_car_id = self.send_car_id
|
||||
new.next_v_pref = self.next_v_pref
|
||||
new.randomGenerator = self.randomGenerator.copy()
|
||||
new.sent = self.sent
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
if self.path != []:
|
||||
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)
|
||||
else:
|
||||
return "Commercial: waiting..."
|
||||
|
||||
class Building(AtomicDEVS):
|
||||
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"):
|
||||
# parent class constructor
|
||||
AtomicDEVS.__init__(self, name)
|
||||
|
||||
# copy of arguments
|
||||
self.IAT_min = IAT_min
|
||||
self.IAT_max = IAT_max
|
||||
self.v_pref_min = v_pref_min
|
||||
self.v_pref_max = v_pref_max
|
||||
self.dv_pos_max = dv_pos_max
|
||||
self.dv_neg_max = dv_neg_max
|
||||
|
||||
# output ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.exit = self.addOutPort(name="exit")
|
||||
self.Q_send = self.q_send
|
||||
self.car_out = self.exit
|
||||
|
||||
# input ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
#self.q_recv = self.addInPort(name="q_recv")
|
||||
self.Q_rack = self.q_rans
|
||||
self.entry = self.addInPort(name="entry")
|
||||
|
||||
# set the state
|
||||
self.state = BuildingState(IAT_min, IAT_max, path, name)
|
||||
self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
|
||||
self.send_max = 1
|
||||
|
||||
self.district = district
|
||||
|
||||
def intTransition(self):
|
||||
mintime = self.timeAdvance()
|
||||
#print("Got mintime: " + str(mintime))
|
||||
self.state.currentTime += mintime
|
||||
|
||||
self.state.send_query_delay -= mintime
|
||||
self.state.send_car_delay -= mintime
|
||||
|
||||
if self.state.send_car_delay == 0:
|
||||
self.state.send_car_delay = INFINITY
|
||||
self.state.send_car_id = self.state.send_query_id
|
||||
self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
|
||||
elif self.state.send_query_delay == 0:
|
||||
self.state.send_query_delay = INFINITY
|
||||
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
mintime = self.timeAdvance()
|
||||
#print("Got mintime: " + str(mintime))
|
||||
currentTime = self.state.currentTime + self.timeAdvance()
|
||||
outputs = {}
|
||||
|
||||
if self.state.send_car_delay == mintime:
|
||||
v_pref = self.state.next_v_pref
|
||||
car = Car(self.state.send_car_id, 0, v_pref, self.dv_pos_max, self.dv_neg_max, currentTime)
|
||||
car.path = self.state.path
|
||||
#self.poke(self.car_out, car)
|
||||
outputs[self.car_out] = [car]
|
||||
elif self.state.send_query_delay == mintime:
|
||||
query = Query(self.state.send_query_id)
|
||||
#self.poke(self.Q_send, query)
|
||||
outputs[self.Q_send] = [query]
|
||||
return outputs
|
||||
|
||||
def timeAdvance(self):
|
||||
return min(self.state.send_query_delay, self.state.send_car_delay)
|
||||
|
||||
def extTransition(self, inputs):
|
||||
#print("ELAPSED: " + str(self.elapsed))
|
||||
#print("Got elapsed: " + str(self.elapsed))
|
||||
self.state.currentTime += self.elapsed
|
||||
self.state.send_query_delay -= self.elapsed
|
||||
self.state.send_car_delay -= self.elapsed
|
||||
queryAcks = inputs.get(self.Q_rack, [])
|
||||
for queryAck in queryAcks:
|
||||
if self.state.send_car_id == queryAck.ID and (self.state.sent < self.send_max):
|
||||
self.state.send_car_delay = queryAck.t_until_dep
|
||||
if queryAck.t_until_dep < 20000:
|
||||
self.state.sent += 1
|
||||
# Generate the next situation
|
||||
if self.state.sent < self.send_max:
|
||||
self.state.send_query_delay = self.randomGenerator.uniform(self.IAT_min, self.IAT_max)
|
||||
#self.state.send_query_id = int(self.randomGenerator.uniform(0, 100000))
|
||||
self.state.send_query_id += 1000000
|
||||
return self.state
|
||||
|
||||
class Residence(Building):
|
||||
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):
|
||||
Building.__init__(self, True, district, path=path, name=name)
|
||||
|
||||
class CommercialState(object):
|
||||
def __init__(self, car):
|
||||
self.car = car
|
||||
|
||||
def __str__(self):
|
||||
return "CommercialState"
|
||||
|
||||
def copy(self):
|
||||
return CommercialState(self.car)
|
||||
|
||||
class Commercial(Building):
|
||||
def __init__(self, district, name="Commercial"):
|
||||
Building.__init__(self, False, district, name=name)
|
||||
self.state = CommercialState(None)
|
||||
self.toCollector = self.addOutPort(name="toCollector")
|
||||
|
||||
def extTransition(self, inputs):
|
||||
return CommercialState(inputs[self.entry][0])
|
||||
|
||||
def intTransition(self):
|
||||
return CommercialState(None)
|
||||
|
||||
def outputFnc(self):
|
||||
return {self.toCollector: [self.state.car]}
|
||||
|
||||
def timeAdvance(self):
|
||||
if self.state.car is None:
|
||||
return INFINITY
|
||||
else:
|
||||
return 0.0
|
||||
|
||||
class RoadSegmentState():
|
||||
def __init__(self):
|
||||
self.cars_present = []
|
||||
self.query_buffer = []
|
||||
self.deny_list = []
|
||||
self.reserved = False
|
||||
self.send_query_delay = INFINITY
|
||||
self.send_query_id = None
|
||||
self.send_ack_delay = INFINITY
|
||||
self.send_ack_id = None
|
||||
self.send_car_delay = INFINITY
|
||||
self.send_car_id = None
|
||||
self.last_car = None
|
||||
|
||||
def __eq__(self, other):
|
||||
if self.query_buffer != other.query_buffer:
|
||||
return False
|
||||
if not (self.send_query_delay == other.send_query_delay and
|
||||
self.send_ack_delay == other.send_ack_delay and
|
||||
self.send_car_delay == other.send_car_delay and
|
||||
self.send_query_id == other.send_query_id and
|
||||
self.send_ack_id == other.send_ack_id and
|
||||
self.send_car_id == other.send_car_id):
|
||||
return False
|
||||
if self.reserved != other.reserved:
|
||||
return False
|
||||
if len(self.cars_present) != len(other.cars_present):
|
||||
return False
|
||||
for c1, c2 in zip(self.cars_present, other.cars_present):
|
||||
if c1 != c2:
|
||||
return False
|
||||
if self.last_car != other.last_car:
|
||||
return False
|
||||
if len(self.deny_list) != len(other.deny_list):
|
||||
return False
|
||||
for q1, q2 in zip(self.deny_list, other.deny_list):
|
||||
if q1 != q2:
|
||||
return False
|
||||
return True
|
||||
|
||||
def copy(self):
|
||||
new = RoadSegmentState()
|
||||
new.cars_present = [c.copy() for c in self.cars_present]
|
||||
new.deny_list = [q.copy() for q in self.deny_list]
|
||||
new.query_buffer = list(self.query_buffer)
|
||||
new.reserved = self.reserved
|
||||
new.send_query_delay = self.send_query_delay
|
||||
new.send_query_id = self.send_query_id
|
||||
new.send_ack_delay = self.send_ack_delay
|
||||
new.send_ack_id = self.send_ack_id
|
||||
new.send_car_delay = self.send_car_delay
|
||||
new.send_car_id = self.send_car_id
|
||||
new.last_car = self.last_car
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
string = "Road segment: cars_present = ["
|
||||
for i in self.cars_present:
|
||||
string += str(i.ID) + ", "
|
||||
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)
|
||||
|
||||
class RoadSegment(AtomicDEVS):
|
||||
def __init__(self, district, load, l = 100.0, v_max = 18.0, observ_delay = 0.1, name = "RoadSegment"):
|
||||
AtomicDEVS.__init__(self, name)
|
||||
|
||||
# arguments
|
||||
self.l = float(l)
|
||||
self.v_max = v_max
|
||||
self.observ_delay = observ_delay
|
||||
self.district = district
|
||||
self.load = load
|
||||
|
||||
# in-ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
self.q_recv = self.addInPort(name="q_recv")
|
||||
self.car_in = self.addInPort(name="car_in")
|
||||
self.entries = self.addInPort(name="entries")
|
||||
self.q_rans_bs = self.addInPort(name="q_rans_bs")
|
||||
self.q_recv_bs = self.addInPort(name="q_recv_bs")
|
||||
# compatibility bindings...
|
||||
self.Q_recv = self.q_recv
|
||||
self.Q_rack = self.q_rans
|
||||
|
||||
# out-ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.car_out = self.addOutPort(name="car_out")
|
||||
self.exits = self.addOutPort(name="exits")
|
||||
|
||||
self.q_sans_bs = self.addOutPort(name="q_sans_bs")
|
||||
# compatibility bindings...
|
||||
self.Q_send = self.q_send
|
||||
self.Q_sack = self.q_sans
|
||||
|
||||
self.state = RoadSegmentState()
|
||||
|
||||
def extTransition(self, inputs):
|
||||
queries = inputs.get(self.Q_recv, [])
|
||||
queries.extend(inputs.get(self.q_recv_bs, []))
|
||||
cars = inputs.get(self.car_in, [])
|
||||
cars.extend(inputs.get(self.entries, []))
|
||||
acks = inputs.get(self.Q_rack, [])
|
||||
acks.extend(inputs.get(self.q_rans_bs, []))
|
||||
|
||||
self.state.send_query_delay -= self.elapsed
|
||||
self.state.send_ack_delay -= self.elapsed
|
||||
self.state.send_car_delay -= self.elapsed
|
||||
|
||||
for query in queries:
|
||||
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)):
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = query.ID
|
||||
self.state.reserved = True
|
||||
else:
|
||||
self.state.query_buffer.append(query.ID)
|
||||
self.state.deny_list.append(query)
|
||||
if self.state.send_ack_delay == INFINITY:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = query.ID
|
||||
self.state.last_car = query.ID
|
||||
for car in self.state.cars_present:
|
||||
car.remaining_x -= self.elapsed * car.v
|
||||
|
||||
for car in cars:
|
||||
self.state.last_car = None
|
||||
car.remaining_x = self.l
|
||||
self.state.cars_present.append(car)
|
||||
|
||||
if len(self.state.cars_present) != 1:
|
||||
for other_car in self.state.cars_present:
|
||||
other_car.v = 0
|
||||
self.state.send_query_delay = INFINITY
|
||||
self.state.send_ack_delay = INFINITY
|
||||
self.state.send_car_delay = INFINITY
|
||||
else:
|
||||
self.state.send_query_delay = 0
|
||||
self.state.send_query_id = car.ID
|
||||
if self.state.cars_present[-1].v == 0:
|
||||
t_to_dep = INFINITY
|
||||
else:
|
||||
t_to_dep = max(0, self.l/self.state.cars_present[-1].v)
|
||||
self.state.send_car_delay = t_to_dep
|
||||
self.state.send_car_id = car.ID
|
||||
|
||||
for ack in acks:
|
||||
if (len(self.state.cars_present) == 1) and (ack.ID == self.state.cars_present[0].ID):
|
||||
car = self.state.cars_present[0]
|
||||
t_no_col = ack.t_until_dep
|
||||
v_old = car.v
|
||||
v_pref = car.v_pref
|
||||
remaining_x = car.remaining_x
|
||||
|
||||
if t_no_col + 1 == t_no_col:
|
||||
v_new = 0
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
v_ideal = remaining_x / max(t_no_col, remaining_x / min(v_pref, self.v_max))
|
||||
diff = v_ideal - v_old
|
||||
if diff < 0:
|
||||
if -diff > car.dv_neg_max:
|
||||
diff = -car.dv_neg_max
|
||||
elif diff > 0:
|
||||
if diff > car.dv_pos_max:
|
||||
diff = car.dv_pos_max
|
||||
v_new = v_old + diff
|
||||
if v_new == 0:
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
t_until_dep = car.remaining_x / v_new
|
||||
|
||||
car.v = v_new
|
||||
|
||||
t_until_dep = max(0, t_until_dep)
|
||||
if t_until_dep > self.state.send_car_delay and self.state.last_car is not None:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = self.state.last_car
|
||||
self.state.send_car_delay = t_until_dep
|
||||
self.state.send_car_id = ack.ID
|
||||
|
||||
if t_until_dep == INFINITY:
|
||||
self.state.send_query_id = ack.ID
|
||||
else:
|
||||
self.state.send_query_id = None
|
||||
self.state.send_query_delay = INFINITY
|
||||
return self.state
|
||||
|
||||
def intTransition(self):
|
||||
for _ in range(self.load):
|
||||
pass
|
||||
mintime = self.mintime()
|
||||
self.state.send_query_delay -= mintime
|
||||
self.state.send_ack_delay -= mintime
|
||||
self.state.send_car_delay -= mintime
|
||||
if self.state.send_ack_delay == 0:
|
||||
self.state.send_ack_delay = INFINITY
|
||||
self.state.send_ack_id = None
|
||||
|
||||
elif self.state.send_query_delay == 0:
|
||||
# Just sent a query, now deny all other queries and wait until the current car has left
|
||||
self.state.send_query_delay = INFINITY
|
||||
self.state.send_query_id = None
|
||||
elif self.state.send_car_delay == 0:
|
||||
self.state.cars_present = []
|
||||
self.state.send_car_delay = INFINITY
|
||||
self.state.send_car_id = None
|
||||
|
||||
# A car has left, so we can answer to the first other query we received
|
||||
if len(self.state.query_buffer) != 0:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
#print("Setting %s in %s" % (self.state.query_buffer, self.name))
|
||||
self.state.send_ack_id = self.state.query_buffer.pop()
|
||||
else:
|
||||
# No car is waiting for this segment, so 'unreserve' it
|
||||
self.state.reserved = False
|
||||
if self.state.send_ack_id == None and len(self.state.deny_list) > 0:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
#print("Denylist = %s in %s" % (self.state.deny_list, self.name))
|
||||
self.state.send_ack_id = self.state.deny_list[0].ID
|
||||
self.state.deny_list = self.state.deny_list[1:]
|
||||
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
outputs = {}
|
||||
mintime = self.mintime()
|
||||
if self.state.send_ack_delay == mintime:
|
||||
ackID = self.state.send_ack_id
|
||||
if len(self.state.cars_present) == 0:
|
||||
t_until_dep = 0
|
||||
elif (self.state.cars_present[0].v) == 0:
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
t_until_dep = self.l / self.state.cars_present[0].v
|
||||
ack = QueryAck(ackID, t_until_dep)
|
||||
outputs[self.Q_sack] = [ack]
|
||||
outputs[self.q_sans_bs] = [ack]
|
||||
elif self.state.send_query_delay == mintime:
|
||||
query = Query(self.state.send_query_id)
|
||||
if self.state.cars_present[0].path != []:
|
||||
query.direction = self.state.cars_present[0].path[0]
|
||||
outputs[self.Q_send] = [query]
|
||||
elif self.state.send_car_delay == mintime:
|
||||
car = self.state.cars_present[0]
|
||||
car.distance_travelled += self.l
|
||||
if len(car.path) == 0:
|
||||
outputs[self.exits] = [car]
|
||||
else:
|
||||
outputs[self.car_out] = [car]
|
||||
return outputs
|
||||
|
||||
def mintime(self):
|
||||
return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
|
||||
def timeAdvance(self):
|
||||
#return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
delay = min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
# Take care of floating point errors
|
||||
return max(delay, 0)
|
||||
|
||||
class Road(CoupledDEVS):
|
||||
def __init__(self, district, load, name="Road", segments=5):
|
||||
CoupledDEVS.__init__(self, name)
|
||||
self.segment = []
|
||||
for i in range(segments):
|
||||
self.segment.append(self.addSubModel(RoadSegment(load=load, district=district, name=(name + "_" + str(i)))))
|
||||
|
||||
# in-ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
self.q_recv = self.addInPort(name="q_recv")
|
||||
self.car_in = self.addInPort(name="car_in")
|
||||
self.entries = self.addInPort(name="entries")
|
||||
self.q_rans_bs = self.addInPort(name="q_rans_bs")
|
||||
self.q_recv_bs = self.addInPort(name="q_recv_bs")
|
||||
|
||||
# out-ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.car_out = self.addOutPort(name="car_out")
|
||||
self.exits = self.addOutPort(name="exits")
|
||||
self.q_sans_bs = self.addOutPort(name="q_sans_bs")
|
||||
|
||||
self.connectPorts(self.q_rans, self.segment[-1].q_rans)
|
||||
self.connectPorts(self.q_recv, self.segment[0].q_recv)
|
||||
self.connectPorts(self.car_in, self.segment[0].car_in)
|
||||
self.connectPorts(self.entries, self.segment[0].entries)
|
||||
self.connectPorts(self.q_rans_bs, self.segment[0].q_rans_bs)
|
||||
self.connectPorts(self.q_recv_bs, self.segment[0].q_recv_bs)
|
||||
|
||||
self.connectPorts(self.segment[0].q_sans, self.q_sans)
|
||||
self.connectPorts(self.segment[-1].q_send, self.q_send)
|
||||
self.connectPorts(self.segment[-1].car_out, self.car_out)
|
||||
self.connectPorts(self.segment[0].exits, self.exits)
|
||||
self.connectPorts(self.segment[0].q_sans_bs, self.q_sans_bs)
|
||||
|
||||
for i in range(segments):
|
||||
if i == 0:
|
||||
continue
|
||||
self.connectPorts(self.segment[i].q_sans, self.segment[i-1].q_rans)
|
||||
self.connectPorts(self.segment[i-1].q_send, self.segment[i].q_recv)
|
||||
self.connectPorts(self.segment[i-1].car_out, self.segment[i].car_in)
|
||||
|
||||
class IntersectionState():
|
||||
def __init__(self, switch_signal):
|
||||
self.send_query = []
|
||||
self.send_ack = []
|
||||
self.send_car = []
|
||||
self.queued_queries = []
|
||||
self.id_locations = [None, None, None, None]
|
||||
self.block = vertical
|
||||
self.switch_signal = switch_signal
|
||||
self.ackDir = {}
|
||||
|
||||
def __str__(self):
|
||||
return "ISECT blocking " + str(self.block)
|
||||
return "Intersection: send_query = " + str(self.send_query) + ", send_ack = " + str(self.send_ack) + ", send_car = " + str(self.send_car) + ", block = " + str(self.block)
|
||||
|
||||
def copy(self):
|
||||
new = IntersectionState(self.switch_signal)
|
||||
new.send_query = [q.copy() for q in self.send_query]
|
||||
new.send_ack = [a.copy() for a in self.send_ack]
|
||||
new.send_car = [c.copy() for c in self.send_car]
|
||||
new.queued_queries = [q.copy() for q in self.queued_queries]
|
||||
new.id_locations = list(self.id_locations)
|
||||
new.block = self.block
|
||||
new.switch_signal = self.switch_signal
|
||||
new.ackDir = dict(self.ackDir)
|
||||
return new
|
||||
|
||||
class Intersection(AtomicDEVS):
|
||||
def __init__(self, district, name="Intersection", switch_signal = 30):
|
||||
AtomicDEVS.__init__(self, name=name)
|
||||
self.state = IntersectionState(switch_signal)
|
||||
self.switch_signal_delay = switch_signal
|
||||
self.district = district
|
||||
|
||||
self.q_send = []
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_n"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_e"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_s"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_w"))
|
||||
|
||||
self.q_rans = []
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_n"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_e"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_s"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_w"))
|
||||
|
||||
self.q_recv = []
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_n"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_e"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_s"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_w"))
|
||||
|
||||
self.q_sans = []
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_n"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_e"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_s"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_w"))
|
||||
|
||||
self.car_in = []
|
||||
self.car_in.append(self.addInPort(name="car_in_from_n"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_e"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_s"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_w"))
|
||||
|
||||
self.car_out = []
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_n"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_e"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_s"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_w"))
|
||||
|
||||
def intTransition(self):
|
||||
self.state.switch_signal -= self.timeAdvance()
|
||||
if self.state.switch_signal <= 1e-6:
|
||||
# We switched our traffic lights
|
||||
self.state.switch_signal = self.switch_signal_delay
|
||||
self.state.queued_queries = []
|
||||
self.state.block = vertical if self.state.block == horizontal else horizontal
|
||||
|
||||
for loc, car_id in enumerate(self.state.id_locations):
|
||||
# Notify all cars that got 'green' that they should not continue
|
||||
if car_id is None:
|
||||
continue
|
||||
try:
|
||||
if str(loc) in self.state.block:
|
||||
query = Query(car_id)
|
||||
query.direction = int_to_dir[self.state.ackDir[car_id]]
|
||||
self.state.queued_queries.append(query)
|
||||
except KeyError:
|
||||
pass
|
||||
self.state.send_car = []
|
||||
self.state.send_query = []
|
||||
self.state.send_ack = []
|
||||
return self.state
|
||||
|
||||
def extTransition(self, inputs):
|
||||
# Simple forwarding of all messages
|
||||
# Unless the direction in which it is going is blocked
|
||||
self.state.switch_signal -= self.elapsed
|
||||
for direction in range(4):
|
||||
blocked = str(direction) in self.state.block
|
||||
for car in inputs.get(self.car_in[direction], []):
|
||||
self.state.send_car.append(car)
|
||||
# Got a car, so remove its ID location entry
|
||||
try:
|
||||
del self.state.ackDir[car.ID]
|
||||
self.state.id_locations[self.state.id_locations.index(car.ID)] = None
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
self.state.queued_queries = [query for query in self.state.queued_queries if query.ID != car.ID]
|
||||
for query in inputs.get(self.q_recv[direction], []):
|
||||
self.state.id_locations[direction] = query.ID
|
||||
self.state.ackDir[query.ID] = dir_to_int[query.direction]
|
||||
if blocked:
|
||||
self.state.send_ack.append(QueryAck(query.ID, INFINITY))
|
||||
self.state.queued_queries.append(query)
|
||||
else:
|
||||
self.state.send_query.append(query)
|
||||
for ack in inputs.get(self.q_rans[direction], []):
|
||||
self.state.ackDir[ack.ID] = direction
|
||||
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)):
|
||||
try:
|
||||
self.state.id_locations.index(ack.ID)
|
||||
t_until_dep = INFINITY
|
||||
nquery = Query(ack.ID)
|
||||
nquery.direction = int_to_dir[direction]
|
||||
self.state.queued_queries.append(nquery)
|
||||
except ValueError:
|
||||
continue
|
||||
else:
|
||||
t_until_dep = ack.t_until_dep
|
||||
self.state.send_ack.append(QueryAck(ack.ID, t_until_dep))
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
# Can simply overwrite, as multiple calls to the same destination is impossible
|
||||
toSend = {}
|
||||
new_block = vertical if self.state.block == horizontal else horizontal
|
||||
if self.state.switch_signal == self.timeAdvance():
|
||||
# We switch our traffic lights
|
||||
# Resend all queries for those that are waiting
|
||||
for query in self.state.queued_queries:
|
||||
if str(self.state.id_locations.index(query.ID)) not in new_block:
|
||||
toSend[self.q_send[dir_to_int[query.direction]]] = [query]
|
||||
for loc, car_id in enumerate(self.state.id_locations):
|
||||
# Notify all cars that got 'green' that they should not continue
|
||||
if car_id is None:
|
||||
continue
|
||||
if str(loc) in new_block:
|
||||
toSend[self.q_sans[loc]] = [QueryAck(car_id, INFINITY)]
|
||||
else:
|
||||
try:
|
||||
query = Query(car_id)
|
||||
query.direction = int_to_dir[self.state.ackDir[car_id]]
|
||||
toSend[self.q_send[self.state.ackDir[car_id]]] = [query]
|
||||
except KeyError:
|
||||
pass
|
||||
# We might have some messages to forward too
|
||||
for car in self.state.send_car:
|
||||
dest = car.path.pop(0)
|
||||
toSend[self.car_out[dir_to_int[dest]]] = [car]
|
||||
for query in self.state.send_query:
|
||||
toSend[self.q_send[dir_to_int[query.direction]]] = [query]
|
||||
for ack in self.state.send_ack:
|
||||
# Broadcast for now
|
||||
try:
|
||||
toSend[self.q_sans[self.state.id_locations.index(ack.ID)]] = [ack]
|
||||
except ValueError:
|
||||
pass
|
||||
return toSend
|
||||
|
||||
def timeAdvance(self):
|
||||
if len(self.state.send_car) + len(self.state.send_query) + len(self.state.send_ack) > 0:
|
||||
return 0.0
|
||||
else:
|
||||
return max(self.state.switch_signal, 0.0)
|
||||
|
||||
class CollectorState(object):
|
||||
def __init__(self):
|
||||
self.cars = []
|
||||
|
||||
def copy(self):
|
||||
new = CollectorState()
|
||||
new.cars = list(self.cars)
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
## Print your statistics here!
|
||||
s = "All cars collected:"
|
||||
for car in self.cars:
|
||||
s += "\n\t\t\t%s" % car
|
||||
return s
|
||||
|
||||
class Collector(AtomicDEVS):
|
||||
def __init__(self):
|
||||
AtomicDEVS.__init__(self, "Collector")
|
||||
self.car_in = self.addInPort("car_in")
|
||||
self.state = CollectorState()
|
||||
self.district = 0
|
||||
|
||||
def extTransition(self, inputs):
|
||||
self.state.cars.extend(inputs[self.car_in])
|
||||
return self.state
|
||||
8
models/dist_activity_citylayout/cluster_5/results_AT
Normal file
8
models/dist_activity_citylayout/cluster_5/results_AT
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 1371 1421 1256
|
||||
10000 1274 1314 1288
|
||||
15000 1404 1024 1383
|
||||
20000 1800 1745 1702
|
||||
25000 2016 2041 2021
|
||||
30000 2470 2579 2388
|
||||
35000 2857 2869 2862
|
||||
40000 3311 3336 3341
|
||||
8
models/dist_activity_citylayout/cluster_5/results_CA
Normal file
8
models/dist_activity_citylayout/cluster_5/results_CA
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 1312 1270 1309
|
||||
10000 1236 1217 1219
|
||||
15000 1351 1317 1330
|
||||
20000 1563 1581 1566
|
||||
25000 1794 1791 1802
|
||||
30000 2085 2090 2089
|
||||
35000 2428 2478 2422
|
||||
40000 2825 2827 2896
|
||||
8
models/dist_activity_citylayout/cluster_5/results_CACR
Normal file
8
models/dist_activity_citylayout/cluster_5/results_CACR
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 1242 1247 1227
|
||||
10000 1238 1214 1244
|
||||
15000 1321 1339 1331
|
||||
20000 1543 1555 1566
|
||||
25000 1826 1766 1793
|
||||
30000 2074 2098 2103
|
||||
35000 2428 2493 2450
|
||||
40000 2930 2927 2873
|
||||
8
models/dist_activity_citylayout/cluster_5/results_NO
Normal file
8
models/dist_activity_citylayout/cluster_5/results_NO
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 1306 1325 1312
|
||||
10000 1319 1361 1369
|
||||
15000 1512 1522 1504
|
||||
20000 1754 1789 1747
|
||||
25000 2012 2041 2053
|
||||
30000 2402 2382 2387
|
||||
35000 2814 2812 2815
|
||||
40000 3260 3264 3261
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
from collections import defaultdict
|
||||
|
||||
class CityRelocator(object):
|
||||
def __init__(self):
|
||||
self.server = None
|
||||
self.kernels = 0
|
||||
self.model_ids = []
|
||||
|
||||
def setController(self, controller):
|
||||
self.kernels = controller.kernels
|
||||
self.server = controller.server
|
||||
self.model_ids = controller.model_ids
|
||||
self.districts = defaultdict(list)
|
||||
for m in controller.total_model.componentSet:
|
||||
self.districts[m.district].append(m)
|
||||
self.districts = [self.districts[i] for i in range(len(self.districts))]
|
||||
|
||||
def getRelocations(self, GVT, activities, horizon):
|
||||
# Ignore activities variable
|
||||
# Fetch all models and their activity
|
||||
if GVT < 100.0:
|
||||
# Still in warmup
|
||||
return {}
|
||||
previous_district_allocation = [district[0].location for district in self.districts]
|
||||
relocate = {}
|
||||
district_activities = defaultdict(float)
|
||||
for i in range(self.kernels):
|
||||
for model_id, activity in self.server.getProxy(i).getCompleteActivity().items():
|
||||
district_activities[self.model_ids[model_id].district] += activity
|
||||
district_activities = [district_activities[i] for i in range(len(district_activities))]
|
||||
print("All loads: " + str(district_activities))
|
||||
avg_activity_per_node = float(sum(district_activities)) / self.kernels
|
||||
if avg_activity_per_node < 20:
|
||||
# Not enough nodes to actually profit from the relocation
|
||||
return {}
|
||||
print("Avg: " + str(avg_activity_per_node))
|
||||
running_activity = 0.0
|
||||
district_allocation = []
|
||||
to_allocate = []
|
||||
for district, activity in enumerate(district_activities):
|
||||
if abs(running_activity - avg_activity_per_node) < abs(running_activity - avg_activity_per_node + activity):
|
||||
# Enough activity for this node, so put all these districts there
|
||||
district_allocation.append(to_allocate)
|
||||
running_activity = activity
|
||||
to_allocate = [district]
|
||||
else:
|
||||
running_activity += activity
|
||||
to_allocate.append(district)
|
||||
if len(district_allocation) < self.kernels:
|
||||
# Still have to add the last node
|
||||
district_allocation.append(to_allocate)
|
||||
else:
|
||||
district_allocation[-1].extend(to_allocate)
|
||||
print("Migrating to %s" % district_allocation)
|
||||
for node, districts in enumerate(district_allocation):
|
||||
for district in districts:
|
||||
if previous_district_allocation[district] == node or (previous_district_allocation[district] < node and GVT > horizon):
|
||||
continue
|
||||
print("Moving " + str(district) + " to " + str(node))
|
||||
for model in self.districts[district]:
|
||||
relocate[model.model_id] = node
|
||||
return relocate
|
||||
|
||||
def useLastStateOnly(self):
|
||||
return True
|
||||
770
models/dist_activity_citylayout/custom_activity/trafficModels.py
Normal file
770
models/dist_activity_citylayout/custom_activity/trafficModels.py
Normal file
|
|
@ -0,0 +1,770 @@
|
|||
import sys
|
||||
sys.path.append("../../../src/")
|
||||
from infinity import *
|
||||
from DEVS import *
|
||||
import random
|
||||
|
||||
north = 0
|
||||
east = 1
|
||||
south = 2
|
||||
west = 3
|
||||
vertical = "02"
|
||||
horizontal = "13"
|
||||
dir_to_int = {'n': north, 'e': east, 's': south, 'w': west}
|
||||
int_to_dir = {north: 'n', east: 'e', south: 's', west: 'w'}
|
||||
|
||||
class Car:
|
||||
def __init__(self, ID, v, v_pref, dv_pos_max, dv_neg_max, departure_time):
|
||||
self.ID = ID
|
||||
self.v_pref = v_pref
|
||||
self.dv_pos_max = dv_pos_max
|
||||
self.dv_neg_max = dv_neg_max
|
||||
self.departure_time = departure_time
|
||||
self.distance_travelled = 0
|
||||
self.remaining_x = 0
|
||||
self.v = v
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and
|
||||
self.v_pref == other.v_pref and
|
||||
self.dv_pos_max == other.dv_pos_max and
|
||||
self.dv_neg_max == other.dv_neg_max and
|
||||
self.departure_time == other.departure_time and
|
||||
self.distance_travelled == other.distance_travelled and
|
||||
self.remaining_x == other.remaining_x and
|
||||
self.v == other.v)
|
||||
|
||||
def __str__(self):
|
||||
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)
|
||||
|
||||
def copy(self):
|
||||
car = Car(self.ID, self.v, self.v_pref, self.dv_pos_max, self.dv_neg_max, self.departure_time)
|
||||
car.distance_travelled = self.distance_travelled
|
||||
car.remaining_x = self.remaining_x
|
||||
car.path = list(self.path)
|
||||
return car
|
||||
|
||||
class Query:
|
||||
def __init__(self, ID):
|
||||
self.ID = ID
|
||||
self.direction = ''
|
||||
|
||||
def __str__(self):
|
||||
return "Query: ID = " + str(self.ID)
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and self.direction == other.direction)
|
||||
|
||||
def copy(self):
|
||||
query = Query(self.ID)
|
||||
query.direction = self.direction
|
||||
return query
|
||||
|
||||
class QueryAck:
|
||||
def __init__(self, ID, t_until_dep):
|
||||
self.ID = ID
|
||||
self.t_until_dep = t_until_dep
|
||||
|
||||
def __str__(self):
|
||||
return "Query Ack: ID = " + str(self.ID) + ", t_until_dep = %.3f" % self.t_until_dep
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and self.t_until_dep == other.t_until_dep)
|
||||
|
||||
def copy(self):
|
||||
return QueryAck(self.ID, self.t_until_dep)
|
||||
|
||||
class BuildingState:
|
||||
def __init__(self, IAT_min, IAT_max, path, name):
|
||||
self.currentTime = 0
|
||||
from randomGenerator import RandomGenerator
|
||||
seed = random.random()
|
||||
self.randomGenerator = RandomGenerator(seed)
|
||||
self.send_query_delay = self.randomGenerator.uniform(IAT_min, IAT_max)
|
||||
|
||||
self.send_car_delay = INFINITY
|
||||
self.path = path
|
||||
if path == []:
|
||||
self.send_query_delay = INFINITY
|
||||
|
||||
self.name = name
|
||||
self.send_query_id = int(name.split("_", 1)[1].split("_")[0]) * 1000 + int(name.split("_", 1)[1].split("_")[1])
|
||||
self.send_car_id = self.send_query_id
|
||||
self.next_v_pref = 0
|
||||
self.sent = 0
|
||||
|
||||
def copy(self):
|
||||
new = BuildingState(0, 0, list(self.path), self.name)
|
||||
new.currentTime = self.currentTime
|
||||
new.send_query_delay = self.send_query_delay
|
||||
new.send_car_delay = self.send_car_delay
|
||||
new.send_query_id = self.send_query_id
|
||||
new.send_car_id = self.send_car_id
|
||||
new.next_v_pref = self.next_v_pref
|
||||
new.randomGenerator = self.randomGenerator.copy()
|
||||
new.sent = self.sent
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
if self.path != []:
|
||||
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)
|
||||
else:
|
||||
return "Commercial: waiting..."
|
||||
|
||||
class Building(AtomicDEVS):
|
||||
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"):
|
||||
# parent class constructor
|
||||
AtomicDEVS.__init__(self, name)
|
||||
|
||||
# copy of arguments
|
||||
self.IAT_min = IAT_min
|
||||
self.IAT_max = IAT_max
|
||||
self.v_pref_min = v_pref_min
|
||||
self.v_pref_max = v_pref_max
|
||||
self.dv_pos_max = dv_pos_max
|
||||
self.dv_neg_max = dv_neg_max
|
||||
|
||||
# output ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.exit = self.addOutPort(name="exit")
|
||||
self.Q_send = self.q_send
|
||||
self.car_out = self.exit
|
||||
|
||||
# input ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
#self.q_recv = self.addInPort(name="q_recv")
|
||||
self.Q_rack = self.q_rans
|
||||
self.entry = self.addInPort(name="entry")
|
||||
|
||||
# set the state
|
||||
self.state = BuildingState(IAT_min, IAT_max, path, name)
|
||||
self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
|
||||
self.send_max = 1
|
||||
|
||||
self.district = district
|
||||
|
||||
def intTransition(self):
|
||||
mintime = self.timeAdvance()
|
||||
#print("Got mintime: " + str(mintime))
|
||||
self.state.currentTime += mintime
|
||||
|
||||
self.state.send_query_delay -= mintime
|
||||
self.state.send_car_delay -= mintime
|
||||
|
||||
if self.state.send_car_delay == 0:
|
||||
self.state.send_car_delay = INFINITY
|
||||
self.state.send_car_id = self.state.send_query_id
|
||||
self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
|
||||
elif self.state.send_query_delay == 0:
|
||||
self.state.send_query_delay = INFINITY
|
||||
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
mintime = self.timeAdvance()
|
||||
#print("Got mintime: " + str(mintime))
|
||||
currentTime = self.state.currentTime + self.timeAdvance()
|
||||
outputs = {}
|
||||
|
||||
if self.state.send_car_delay == mintime:
|
||||
v_pref = self.state.next_v_pref
|
||||
car = Car(self.state.send_car_id, 0, v_pref, self.dv_pos_max, self.dv_neg_max, currentTime)
|
||||
car.path = self.state.path
|
||||
#self.poke(self.car_out, car)
|
||||
outputs[self.car_out] = [car]
|
||||
elif self.state.send_query_delay == mintime:
|
||||
query = Query(self.state.send_query_id)
|
||||
#self.poke(self.Q_send, query)
|
||||
outputs[self.Q_send] = [query]
|
||||
return outputs
|
||||
|
||||
def timeAdvance(self):
|
||||
return min(self.state.send_query_delay, self.state.send_car_delay)
|
||||
|
||||
def extTransition(self, inputs):
|
||||
#print("ELAPSED: " + str(self.elapsed))
|
||||
#print("Got elapsed: " + str(self.elapsed))
|
||||
self.state.currentTime += self.elapsed
|
||||
self.state.send_query_delay -= self.elapsed
|
||||
self.state.send_car_delay -= self.elapsed
|
||||
queryAcks = inputs.get(self.Q_rack, [])
|
||||
for queryAck in queryAcks:
|
||||
if self.state.send_car_id == queryAck.ID and (self.state.sent < self.send_max):
|
||||
self.state.send_car_delay = queryAck.t_until_dep
|
||||
if queryAck.t_until_dep < 20000:
|
||||
self.state.sent += 1
|
||||
# Generate the next situation
|
||||
if self.state.sent < self.send_max:
|
||||
self.state.send_query_delay = self.randomGenerator.uniform(self.IAT_min, self.IAT_max)
|
||||
#self.state.send_query_id = int(self.randomGenerator.uniform(0, 100000))
|
||||
self.state.send_query_id += 1000000
|
||||
return self.state
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
return 0 if self.state.send_car_delay == float('inf') else 1
|
||||
|
||||
class Residence(Building):
|
||||
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):
|
||||
Building.__init__(self, True, district, path=path, name=name)
|
||||
|
||||
class CommercialState(object):
|
||||
def __init__(self, car):
|
||||
self.car = car
|
||||
|
||||
def __str__(self):
|
||||
return "CommercialState"
|
||||
|
||||
def copy(self):
|
||||
return CommercialState(self.car)
|
||||
|
||||
class Commercial(Building):
|
||||
def __init__(self, district, name="Commercial"):
|
||||
Building.__init__(self, False, district, name=name)
|
||||
self.state = CommercialState(None)
|
||||
self.toCollector = self.addOutPort(name="toCollector")
|
||||
|
||||
def extTransition(self, inputs):
|
||||
return CommercialState(inputs[self.entry][0])
|
||||
|
||||
def intTransition(self):
|
||||
return CommercialState(None)
|
||||
|
||||
def outputFnc(self):
|
||||
return {self.toCollector: [self.state.car]}
|
||||
|
||||
def timeAdvance(self):
|
||||
if self.state.car is None:
|
||||
return INFINITY
|
||||
else:
|
||||
return 0.0
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
return 0
|
||||
|
||||
class RoadSegmentState():
|
||||
def __init__(self):
|
||||
self.cars_present = []
|
||||
self.query_buffer = []
|
||||
self.deny_list = []
|
||||
self.reserved = False
|
||||
self.send_query_delay = INFINITY
|
||||
self.send_query_id = None
|
||||
self.send_ack_delay = INFINITY
|
||||
self.send_ack_id = None
|
||||
self.send_car_delay = INFINITY
|
||||
self.send_car_id = None
|
||||
self.last_car = None
|
||||
|
||||
def __eq__(self, other):
|
||||
if not (self.send_query_delay == other.send_query_delay and
|
||||
self.send_ack_delay == other.send_ack_delay and
|
||||
self.send_car_delay == other.send_car_delay and
|
||||
self.send_query_id == other.send_query_id and
|
||||
self.send_ack_id == other.send_ack_id and
|
||||
self.send_car_id == other.send_car_id and
|
||||
self.last_car == other.last_car and
|
||||
self.reserved == other.reserved):
|
||||
return False
|
||||
if self.query_buffer != other.query_buffer:
|
||||
return False
|
||||
if len(self.cars_present) != len(other.cars_present):
|
||||
return False
|
||||
for c1, c2 in zip(self.cars_present, other.cars_present):
|
||||
if c1 != c2:
|
||||
return False
|
||||
if len(self.deny_list) != len(other.deny_list):
|
||||
return False
|
||||
for q1, q2 in zip(self.deny_list, other.deny_list):
|
||||
if q1 != q2:
|
||||
return False
|
||||
return True
|
||||
|
||||
def copy(self):
|
||||
new = RoadSegmentState()
|
||||
new.cars_present = [c.copy() for c in self.cars_present]
|
||||
new.query_buffer = list(self.query_buffer)
|
||||
new.deny_list = [q.copy() for q in self.deny_list]
|
||||
new.reserved = self.reserved
|
||||
new.send_query_delay = self.send_query_delay
|
||||
new.send_query_id = self.send_query_id
|
||||
new.send_ack_delay = self.send_ack_delay
|
||||
new.send_ack_id = self.send_ack_id
|
||||
new.send_car_delay = self.send_car_delay
|
||||
new.send_car_id = self.send_car_id
|
||||
new.last_car = self.last_car
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
string = "Road segment: cars_present = ["
|
||||
for i in self.cars_present:
|
||||
string += str(i.ID) + ", "
|
||||
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)
|
||||
|
||||
class RoadSegment(AtomicDEVS):
|
||||
def __init__(self, district, load, l = 100.0, v_max = 18.0, observ_delay = 0.1, name = "RoadSegment"):
|
||||
AtomicDEVS.__init__(self, name)
|
||||
|
||||
# arguments
|
||||
self.l = float(l)
|
||||
self.v_max = v_max
|
||||
self.observ_delay = observ_delay
|
||||
self.district = district
|
||||
self.load = load
|
||||
|
||||
# in-ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
self.q_recv = self.addInPort(name="q_recv")
|
||||
self.car_in = self.addInPort(name="car_in")
|
||||
self.entries = self.addInPort(name="entries")
|
||||
self.q_rans_bs = self.addInPort(name="q_rans_bs")
|
||||
self.q_recv_bs = self.addInPort(name="q_recv_bs")
|
||||
# compatibility bindings...
|
||||
self.Q_recv = self.q_recv
|
||||
self.Q_rack = self.q_rans
|
||||
|
||||
# out-ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.car_out = self.addOutPort(name="car_out")
|
||||
self.exits = self.addOutPort(name="exits")
|
||||
|
||||
self.q_sans_bs = self.addOutPort(name="q_sans_bs")
|
||||
# compatibility bindings...
|
||||
self.Q_send = self.q_send
|
||||
self.Q_sack = self.q_sans
|
||||
|
||||
self.state = RoadSegmentState()
|
||||
|
||||
def extTransition(self, inputs):
|
||||
queries = inputs.get(self.Q_recv, [])
|
||||
queries.extend(inputs.get(self.q_recv_bs, []))
|
||||
cars = inputs.get(self.car_in, [])
|
||||
cars.extend(inputs.get(self.entries, []))
|
||||
acks = inputs.get(self.Q_rack, [])
|
||||
acks.extend(inputs.get(self.q_rans_bs, []))
|
||||
|
||||
self.state.send_query_delay -= self.elapsed
|
||||
self.state.send_ack_delay -= self.elapsed
|
||||
self.state.send_car_delay -= self.elapsed
|
||||
|
||||
for query in queries:
|
||||
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)):
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = query.ID
|
||||
self.state.reserved = True
|
||||
else:
|
||||
self.state.query_buffer.append(query.ID)
|
||||
self.state.deny_list.append(query)
|
||||
if self.state.send_ack_delay == INFINITY:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = query.ID
|
||||
self.state.last_car = query.ID
|
||||
for car in self.state.cars_present:
|
||||
car.remaining_x -= self.elapsed * car.v
|
||||
|
||||
for car in cars:
|
||||
self.state.last_car = None
|
||||
car.remaining_x = self.l
|
||||
self.state.cars_present.append(car)
|
||||
|
||||
if len(self.state.cars_present) != 1:
|
||||
for other_car in self.state.cars_present:
|
||||
other_car.v = 0
|
||||
self.state.send_query_delay = INFINITY
|
||||
self.state.send_ack_delay = INFINITY
|
||||
self.state.send_car_delay = INFINITY
|
||||
else:
|
||||
self.state.send_query_delay = 0
|
||||
self.state.send_query_id = car.ID
|
||||
if self.state.cars_present[-1].v == 0:
|
||||
t_to_dep = INFINITY
|
||||
else:
|
||||
t_to_dep = max(0, self.l/self.state.cars_present[-1].v)
|
||||
self.state.send_car_delay = t_to_dep
|
||||
self.state.send_car_id = car.ID
|
||||
|
||||
for ack in acks:
|
||||
if (len(self.state.cars_present) == 1) and (ack.ID == self.state.cars_present[0].ID):
|
||||
car = self.state.cars_present[0]
|
||||
t_no_col = ack.t_until_dep
|
||||
v_old = car.v
|
||||
v_pref = car.v_pref
|
||||
remaining_x = car.remaining_x
|
||||
|
||||
if t_no_col + 1 == t_no_col:
|
||||
v_new = 0
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
v_ideal = remaining_x / max(t_no_col, remaining_x / min(v_pref, self.v_max))
|
||||
diff = v_ideal - v_old
|
||||
if diff < 0:
|
||||
if -diff > car.dv_neg_max:
|
||||
diff = -car.dv_neg_max
|
||||
elif diff > 0:
|
||||
if diff > car.dv_pos_max:
|
||||
diff = car.dv_pos_max
|
||||
v_new = v_old + diff
|
||||
if v_new == 0:
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
t_until_dep = car.remaining_x / v_new
|
||||
|
||||
car.v = v_new
|
||||
|
||||
t_until_dep = max(0, t_until_dep)
|
||||
if t_until_dep > self.state.send_car_delay and self.state.last_car is not None:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = self.state.last_car
|
||||
self.state.send_car_delay = t_until_dep
|
||||
self.state.send_car_id = ack.ID
|
||||
|
||||
if t_until_dep == INFINITY:
|
||||
self.state.send_query_id = ack.ID
|
||||
else:
|
||||
self.state.send_query_id = None
|
||||
self.state.send_query_delay = INFINITY
|
||||
return self.state
|
||||
|
||||
def intTransition(self):
|
||||
for _ in range(self.load):
|
||||
pass
|
||||
mintime = self.mintime()
|
||||
self.state.send_query_delay -= mintime
|
||||
self.state.send_ack_delay -= mintime
|
||||
self.state.send_car_delay -= mintime
|
||||
if self.state.send_ack_delay == 0:
|
||||
self.state.send_ack_delay = INFINITY
|
||||
self.state.send_ack_id = None
|
||||
|
||||
elif self.state.send_query_delay == 0:
|
||||
# Just sent a query, now deny all other queries and wait until the current car has left
|
||||
self.state.send_query_delay = INFINITY
|
||||
self.state.send_query_id = None
|
||||
elif self.state.send_car_delay == 0:
|
||||
self.state.cars_present = []
|
||||
self.state.send_car_delay = INFINITY
|
||||
self.state.send_car_id = None
|
||||
|
||||
# A car has left, so we can answer to the first other query we received
|
||||
if len(self.state.query_buffer) != 0:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
#print("Setting %s in %s" % (self.state.query_buffer, self.name))
|
||||
self.state.send_ack_id = self.state.query_buffer.pop()
|
||||
else:
|
||||
# No car is waiting for this segment, so 'unreserve' it
|
||||
self.state.reserved = False
|
||||
if self.state.send_ack_id == None and len(self.state.deny_list) > 0:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
#print("Denylist = %s in %s" % (self.state.deny_list, self.name))
|
||||
self.state.send_ack_id = self.state.deny_list[0].ID
|
||||
self.state.deny_list = self.state.deny_list[1:]
|
||||
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
outputs = {}
|
||||
mintime = self.mintime()
|
||||
if self.state.send_ack_delay == mintime:
|
||||
ackID = self.state.send_ack_id
|
||||
if len(self.state.cars_present) == 0:
|
||||
t_until_dep = 0
|
||||
elif (self.state.cars_present[0].v) == 0:
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
t_until_dep = self.l / self.state.cars_present[0].v
|
||||
ack = QueryAck(ackID, t_until_dep)
|
||||
outputs[self.Q_sack] = [ack]
|
||||
outputs[self.q_sans_bs] = [ack]
|
||||
elif self.state.send_query_delay == mintime:
|
||||
query = Query(self.state.send_query_id)
|
||||
if self.state.cars_present[0].path != []:
|
||||
query.direction = self.state.cars_present[0].path[0]
|
||||
outputs[self.Q_send] = [query]
|
||||
elif self.state.send_car_delay == mintime:
|
||||
car = self.state.cars_present[0]
|
||||
car.distance_travelled += self.l
|
||||
if len(car.path) == 0:
|
||||
outputs[self.exits] = [car]
|
||||
else:
|
||||
outputs[self.car_out] = [car]
|
||||
return outputs
|
||||
|
||||
def mintime(self):
|
||||
return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
|
||||
def timeAdvance(self):
|
||||
#return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
delay = min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
# Take care of floating point errors
|
||||
return max(delay, 0)
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
# If a car has collided, no activity is here
|
||||
return 1 if len(self.state.cars_present) == 1 else 0
|
||||
|
||||
class Road(CoupledDEVS):
|
||||
def __init__(self, district, load, name="Road", segments=5):
|
||||
CoupledDEVS.__init__(self, name)
|
||||
self.segment = []
|
||||
for i in range(segments):
|
||||
self.segment.append(self.addSubModel(RoadSegment(load=load, district=district, name=(name + "_" + str(i)))))
|
||||
|
||||
# in-ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
self.q_recv = self.addInPort(name="q_recv")
|
||||
self.car_in = self.addInPort(name="car_in")
|
||||
self.entries = self.addInPort(name="entries")
|
||||
self.q_rans_bs = self.addInPort(name="q_rans_bs")
|
||||
self.q_recv_bs = self.addInPort(name="q_recv_bs")
|
||||
|
||||
# out-ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.car_out = self.addOutPort(name="car_out")
|
||||
self.exits = self.addOutPort(name="exits")
|
||||
self.q_sans_bs = self.addOutPort(name="q_sans_bs")
|
||||
|
||||
self.connectPorts(self.q_rans, self.segment[-1].q_rans)
|
||||
self.connectPorts(self.q_recv, self.segment[0].q_recv)
|
||||
self.connectPorts(self.car_in, self.segment[0].car_in)
|
||||
self.connectPorts(self.entries, self.segment[0].entries)
|
||||
self.connectPorts(self.q_rans_bs, self.segment[0].q_rans_bs)
|
||||
self.connectPorts(self.q_recv_bs, self.segment[0].q_recv_bs)
|
||||
|
||||
self.connectPorts(self.segment[0].q_sans, self.q_sans)
|
||||
self.connectPorts(self.segment[-1].q_send, self.q_send)
|
||||
self.connectPorts(self.segment[-1].car_out, self.car_out)
|
||||
self.connectPorts(self.segment[0].exits, self.exits)
|
||||
self.connectPorts(self.segment[0].q_sans_bs, self.q_sans_bs)
|
||||
|
||||
for i in range(segments):
|
||||
if i == 0:
|
||||
continue
|
||||
self.connectPorts(self.segment[i].q_sans, self.segment[i-1].q_rans)
|
||||
self.connectPorts(self.segment[i-1].q_send, self.segment[i].q_recv)
|
||||
self.connectPorts(self.segment[i-1].car_out, self.segment[i].car_in)
|
||||
|
||||
class IntersectionState():
|
||||
def __init__(self, switch_signal):
|
||||
self.send_query = []
|
||||
self.send_ack = []
|
||||
self.send_car = []
|
||||
self.queued_queries = []
|
||||
self.id_locations = [None, None, None, None]
|
||||
self.block = vertical
|
||||
self.switch_signal = switch_signal
|
||||
self.ackDir = {}
|
||||
|
||||
def __str__(self):
|
||||
return "ISECT blocking " + str(self.block)
|
||||
return "Intersection: send_query = " + str(self.send_query) + ", send_ack = " + str(self.send_ack) + ", send_car = " + str(self.send_car) + ", block = " + str(self.block)
|
||||
|
||||
def copy(self):
|
||||
new = IntersectionState(self.switch_signal)
|
||||
new.send_query = [q.copy() for q in self.send_query]
|
||||
new.send_ack = [a.copy() for a in self.send_ack]
|
||||
new.send_car = [c.copy() for c in self.send_car]
|
||||
new.queued_queries = [q.copy() for q in self.queued_queries]
|
||||
new.id_locations = list(self.id_locations)
|
||||
new.block = self.block
|
||||
new.switch_signal = self.switch_signal
|
||||
new.ackDir = dict(self.ackDir)
|
||||
return new
|
||||
|
||||
class Intersection(AtomicDEVS):
|
||||
def __init__(self, district, name="Intersection", switch_signal = 30):
|
||||
AtomicDEVS.__init__(self, name=name)
|
||||
self.state = IntersectionState(switch_signal)
|
||||
self.switch_signal_delay = switch_signal
|
||||
self.district = district
|
||||
|
||||
self.q_send = []
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_n"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_e"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_s"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_w"))
|
||||
|
||||
self.q_rans = []
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_n"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_e"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_s"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_w"))
|
||||
|
||||
self.q_recv = []
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_n"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_e"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_s"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_w"))
|
||||
|
||||
self.q_sans = []
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_n"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_e"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_s"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_w"))
|
||||
|
||||
self.car_in = []
|
||||
self.car_in.append(self.addInPort(name="car_in_from_n"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_e"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_s"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_w"))
|
||||
|
||||
self.car_out = []
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_n"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_e"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_s"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_w"))
|
||||
|
||||
def intTransition(self):
|
||||
self.state.switch_signal -= self.timeAdvance()
|
||||
if self.state.switch_signal <= 1e-6:
|
||||
# We switched our traffic lights
|
||||
self.state.switch_signal = self.switch_signal_delay
|
||||
self.state.queued_queries = []
|
||||
self.state.block = vertical if self.state.block == horizontal else horizontal
|
||||
|
||||
for loc, car_id in enumerate(self.state.id_locations):
|
||||
# Notify all cars that got 'green' that they should not continue
|
||||
if car_id is None:
|
||||
continue
|
||||
try:
|
||||
if str(loc) in self.state.block:
|
||||
query = Query(car_id)
|
||||
query.direction = int_to_dir[self.state.ackDir[car_id]]
|
||||
self.state.queued_queries.append(query)
|
||||
except KeyError:
|
||||
pass
|
||||
self.state.send_car = []
|
||||
self.state.send_query = []
|
||||
self.state.send_ack = []
|
||||
return self.state
|
||||
|
||||
def extTransition(self, inputs):
|
||||
# Simple forwarding of all messages
|
||||
# Unless the direction in which it is going is blocked
|
||||
self.state.switch_signal -= self.elapsed
|
||||
for direction in range(4):
|
||||
blocked = str(direction) in self.state.block
|
||||
for car in inputs.get(self.car_in[direction], []):
|
||||
self.state.send_car.append(car)
|
||||
# Got a car, so remove its ID location entry
|
||||
try:
|
||||
del self.state.ackDir[car.ID]
|
||||
self.state.id_locations[self.state.id_locations.index(car.ID)] = None
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
self.state.queued_queries = [query for query in self.state.queued_queries if query.ID != car.ID]
|
||||
for query in inputs.get(self.q_recv[direction], []):
|
||||
self.state.id_locations[direction] = query.ID
|
||||
self.state.ackDir[query.ID] = dir_to_int[query.direction]
|
||||
if blocked:
|
||||
self.state.send_ack.append(QueryAck(query.ID, INFINITY))
|
||||
self.state.queued_queries.append(query)
|
||||
else:
|
||||
self.state.send_query.append(query)
|
||||
for ack in inputs.get(self.q_rans[direction], []):
|
||||
self.state.ackDir[ack.ID] = direction
|
||||
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)):
|
||||
try:
|
||||
self.state.id_locations.index(ack.ID)
|
||||
t_until_dep = INFINITY
|
||||
nquery = Query(ack.ID)
|
||||
nquery.direction = int_to_dir[direction]
|
||||
self.state.queued_queries.append(nquery)
|
||||
except ValueError:
|
||||
continue
|
||||
else:
|
||||
t_until_dep = ack.t_until_dep
|
||||
self.state.send_ack.append(QueryAck(ack.ID, t_until_dep))
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
# Can simply overwrite, as multiple calls to the same destination is impossible
|
||||
toSend = {}
|
||||
new_block = vertical if self.state.block == horizontal else horizontal
|
||||
if self.state.switch_signal == self.timeAdvance():
|
||||
# We switch our traffic lights
|
||||
# Resend all queries for those that are waiting
|
||||
for query in self.state.queued_queries:
|
||||
if str(self.state.id_locations.index(query.ID)) not in new_block:
|
||||
toSend[self.q_send[dir_to_int[query.direction]]] = [query]
|
||||
for loc, car_id in enumerate(self.state.id_locations):
|
||||
# Notify all cars that got 'green' that they should not continue
|
||||
if car_id is None:
|
||||
continue
|
||||
if str(loc) in new_block:
|
||||
toSend[self.q_sans[loc]] = [QueryAck(car_id, INFINITY)]
|
||||
else:
|
||||
try:
|
||||
query = Query(car_id)
|
||||
query.direction = int_to_dir[self.state.ackDir[car_id]]
|
||||
toSend[self.q_send[self.state.ackDir[car_id]]] = [query]
|
||||
except KeyError:
|
||||
pass
|
||||
# We might have some messages to forward too
|
||||
for car in self.state.send_car:
|
||||
dest = car.path.pop(0)
|
||||
toSend[self.car_out[dir_to_int[dest]]] = [car]
|
||||
for query in self.state.send_query:
|
||||
toSend[self.q_send[dir_to_int[query.direction]]] = [query]
|
||||
for ack in self.state.send_ack:
|
||||
# Broadcast for now
|
||||
try:
|
||||
toSend[self.q_sans[self.state.id_locations.index(ack.ID)]] = [ack]
|
||||
except ValueError:
|
||||
pass
|
||||
return toSend
|
||||
|
||||
def timeAdvance(self):
|
||||
if len(self.state.send_car) + len(self.state.send_query) + len(self.state.send_ack) > 0:
|
||||
return 0.0
|
||||
else:
|
||||
return max(self.state.switch_signal, 0.0)
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
return len(self.state.send_car)
|
||||
|
||||
class CollectorState(object):
|
||||
def __init__(self):
|
||||
self.cars = []
|
||||
|
||||
def copy(self):
|
||||
new = CollectorState()
|
||||
new.cars = list(self.cars)
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
## Print your statistics here!
|
||||
s = "All cars collected:"
|
||||
for car in self.cars:
|
||||
s += "\n\t\t\t%s" % car
|
||||
return s
|
||||
|
||||
class Collector(AtomicDEVS):
|
||||
def __init__(self):
|
||||
AtomicDEVS.__init__(self, "Collector")
|
||||
self.car_in = self.addInPort("car_in")
|
||||
self.state = CollectorState()
|
||||
self.district = 0
|
||||
|
||||
def extTransition(self, inputs):
|
||||
self.state.cars.extend(inputs[self.car_in])
|
||||
return self.state
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
return 0
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
from collections import defaultdict
|
||||
|
||||
class CityRelocator(object):
|
||||
def __init__(self):
|
||||
self.server = None
|
||||
self.kernels = 0
|
||||
self.model_ids = []
|
||||
|
||||
def setController(self, controller):
|
||||
self.kernels = controller.kernels
|
||||
self.server = controller.server
|
||||
self.model_ids = controller.model_ids
|
||||
self.districts = defaultdict(list)
|
||||
for m in controller.total_model.componentSet:
|
||||
self.districts[m.district].append(m)
|
||||
self.districts = [self.districts[i] for i in range(len(self.districts))]
|
||||
|
||||
def getRelocations(self, GVT, activities, horizon):
|
||||
# Ignore activities variable
|
||||
# Fetch all models and their activity
|
||||
if GVT < 100.0:
|
||||
# Still in warmup
|
||||
return {}
|
||||
previous_district_allocation = [district[0].location for district in self.districts]
|
||||
relocate = {}
|
||||
district_activities = defaultdict(float)
|
||||
for i in range(self.kernels):
|
||||
for model_id, activity in self.server.getProxy(i).getCompleteActivity().items():
|
||||
district_activities[self.model_ids[model_id].district] += activity
|
||||
district_activities = [district_activities[i] for i in range(len(district_activities))]
|
||||
print("All loads: " + str(district_activities))
|
||||
# Shift the loads a little to 'predict the future'
|
||||
new_district_activities = list(district_activities)
|
||||
for index in range(len(district_activities)):
|
||||
leaving = district_activities[index] * (0.0015 * horizon)
|
||||
new_district_activities[index] -= leaving
|
||||
if index != len(district_activities) - 1:
|
||||
if index < 5:
|
||||
arrived = 0
|
||||
else:
|
||||
commercials_left = float(10-index)
|
||||
arrived = leaving * ((commercials_left - 1) / (commercials_left))
|
||||
new_district_activities[index+1] += (leaving - arrived)
|
||||
print("Guessed loads: " + str(new_district_activities))
|
||||
district_activities = new_district_activities
|
||||
avg_activity_per_node = float(sum(district_activities)) / self.kernels
|
||||
if avg_activity_per_node < 20:
|
||||
# Not enough nodes to actually profit from the relocation
|
||||
return {}
|
||||
running_activity = 0.0
|
||||
district_allocation = []
|
||||
to_allocate = []
|
||||
for district, activity in enumerate(district_activities):
|
||||
if abs(running_activity - avg_activity_per_node) < abs(running_activity - avg_activity_per_node + activity):
|
||||
# Enough activity for this node, so put all these districts there
|
||||
district_allocation.append(to_allocate)
|
||||
running_activity = activity
|
||||
to_allocate = [district]
|
||||
else:
|
||||
running_activity += activity
|
||||
to_allocate.append(district)
|
||||
if len(district_allocation) < self.kernels:
|
||||
# Still have to add the last node
|
||||
district_allocation.append(to_allocate)
|
||||
else:
|
||||
district_allocation[-1].extend(to_allocate)
|
||||
print("Migrating to %s" % district_allocation)
|
||||
for node, districts in enumerate(district_allocation):
|
||||
for district in districts:
|
||||
if previous_district_allocation[district] == node or (previous_district_allocation[district] < node and GVT > horizon):
|
||||
continue
|
||||
print("Moving " + str(district) + " to " + str(node))
|
||||
for model in self.districts[district]:
|
||||
relocate[model.model_id] = node
|
||||
return relocate
|
||||
|
||||
def useLastStateOnly(self):
|
||||
return True
|
||||
|
|
@ -0,0 +1,770 @@
|
|||
import sys
|
||||
sys.path.append("../../../src/")
|
||||
from infinity import *
|
||||
from DEVS import *
|
||||
import random
|
||||
|
||||
north = 0
|
||||
east = 1
|
||||
south = 2
|
||||
west = 3
|
||||
vertical = "02"
|
||||
horizontal = "13"
|
||||
dir_to_int = {'n': north, 'e': east, 's': south, 'w': west}
|
||||
int_to_dir = {north: 'n', east: 'e', south: 's', west: 'w'}
|
||||
|
||||
class Car:
|
||||
def __init__(self, ID, v, v_pref, dv_pos_max, dv_neg_max, departure_time):
|
||||
self.ID = ID
|
||||
self.v_pref = v_pref
|
||||
self.dv_pos_max = dv_pos_max
|
||||
self.dv_neg_max = dv_neg_max
|
||||
self.departure_time = departure_time
|
||||
self.distance_travelled = 0
|
||||
self.remaining_x = 0
|
||||
self.v = v
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and
|
||||
self.v_pref == other.v_pref and
|
||||
self.dv_pos_max == other.dv_pos_max and
|
||||
self.dv_neg_max == other.dv_neg_max and
|
||||
self.departure_time == other.departure_time and
|
||||
self.distance_travelled == other.distance_travelled and
|
||||
self.remaining_x == other.remaining_x and
|
||||
self.v == other.v)
|
||||
|
||||
def __str__(self):
|
||||
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)
|
||||
|
||||
def copy(self):
|
||||
car = Car(self.ID, self.v, self.v_pref, self.dv_pos_max, self.dv_neg_max, self.departure_time)
|
||||
car.distance_travelled = self.distance_travelled
|
||||
car.remaining_x = self.remaining_x
|
||||
car.path = list(self.path)
|
||||
return car
|
||||
|
||||
class Query:
|
||||
def __init__(self, ID):
|
||||
self.ID = ID
|
||||
self.direction = ''
|
||||
|
||||
def __str__(self):
|
||||
return "Query: ID = " + str(self.ID)
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and self.direction == other.direction)
|
||||
|
||||
def copy(self):
|
||||
query = Query(self.ID)
|
||||
query.direction = self.direction
|
||||
return query
|
||||
|
||||
class QueryAck:
|
||||
def __init__(self, ID, t_until_dep):
|
||||
self.ID = ID
|
||||
self.t_until_dep = t_until_dep
|
||||
|
||||
def __str__(self):
|
||||
return "Query Ack: ID = " + str(self.ID) + ", t_until_dep = %.3f" % self.t_until_dep
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and self.t_until_dep == other.t_until_dep)
|
||||
|
||||
def copy(self):
|
||||
return QueryAck(self.ID, self.t_until_dep)
|
||||
|
||||
class BuildingState:
|
||||
def __init__(self, IAT_min, IAT_max, path, name):
|
||||
self.currentTime = 0
|
||||
from randomGenerator import RandomGenerator
|
||||
seed = random.random()
|
||||
self.randomGenerator = RandomGenerator(seed)
|
||||
self.send_query_delay = self.randomGenerator.uniform(IAT_min, IAT_max)
|
||||
|
||||
self.send_car_delay = INFINITY
|
||||
self.path = path
|
||||
if path == []:
|
||||
self.send_query_delay = INFINITY
|
||||
|
||||
self.name = name
|
||||
self.send_query_id = int(name.split("_", 1)[1].split("_")[0]) * 1000 + int(name.split("_", 1)[1].split("_")[1])
|
||||
self.send_car_id = self.send_query_id
|
||||
self.next_v_pref = 0
|
||||
self.sent = 0
|
||||
|
||||
def copy(self):
|
||||
new = BuildingState(0, 0, list(self.path), self.name)
|
||||
new.currentTime = self.currentTime
|
||||
new.send_query_delay = self.send_query_delay
|
||||
new.send_car_delay = self.send_car_delay
|
||||
new.send_query_id = self.send_query_id
|
||||
new.send_car_id = self.send_car_id
|
||||
new.next_v_pref = self.next_v_pref
|
||||
new.randomGenerator = self.randomGenerator.copy()
|
||||
new.sent = self.sent
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
if self.path != []:
|
||||
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)
|
||||
else:
|
||||
return "Commercial: waiting..."
|
||||
|
||||
class Building(AtomicDEVS):
|
||||
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"):
|
||||
# parent class constructor
|
||||
AtomicDEVS.__init__(self, name)
|
||||
|
||||
# copy of arguments
|
||||
self.IAT_min = IAT_min
|
||||
self.IAT_max = IAT_max
|
||||
self.v_pref_min = v_pref_min
|
||||
self.v_pref_max = v_pref_max
|
||||
self.dv_pos_max = dv_pos_max
|
||||
self.dv_neg_max = dv_neg_max
|
||||
|
||||
# output ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.exit = self.addOutPort(name="exit")
|
||||
self.Q_send = self.q_send
|
||||
self.car_out = self.exit
|
||||
|
||||
# input ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
#self.q_recv = self.addInPort(name="q_recv")
|
||||
self.Q_rack = self.q_rans
|
||||
self.entry = self.addInPort(name="entry")
|
||||
|
||||
# set the state
|
||||
self.state = BuildingState(IAT_min, IAT_max, path, name)
|
||||
self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
|
||||
self.send_max = 1
|
||||
|
||||
self.district = district
|
||||
|
||||
def intTransition(self):
|
||||
mintime = self.timeAdvance()
|
||||
#print("Got mintime: " + str(mintime))
|
||||
self.state.currentTime += mintime
|
||||
|
||||
self.state.send_query_delay -= mintime
|
||||
self.state.send_car_delay -= mintime
|
||||
|
||||
if self.state.send_car_delay == 0:
|
||||
self.state.send_car_delay = INFINITY
|
||||
self.state.send_car_id = self.state.send_query_id
|
||||
self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
|
||||
elif self.state.send_query_delay == 0:
|
||||
self.state.send_query_delay = INFINITY
|
||||
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
mintime = self.timeAdvance()
|
||||
#print("Got mintime: " + str(mintime))
|
||||
currentTime = self.state.currentTime + self.timeAdvance()
|
||||
outputs = {}
|
||||
|
||||
if self.state.send_car_delay == mintime:
|
||||
v_pref = self.state.next_v_pref
|
||||
car = Car(self.state.send_car_id, 0, v_pref, self.dv_pos_max, self.dv_neg_max, currentTime)
|
||||
car.path = self.state.path
|
||||
#self.poke(self.car_out, car)
|
||||
outputs[self.car_out] = [car]
|
||||
elif self.state.send_query_delay == mintime:
|
||||
query = Query(self.state.send_query_id)
|
||||
#self.poke(self.Q_send, query)
|
||||
outputs[self.Q_send] = [query]
|
||||
return outputs
|
||||
|
||||
def timeAdvance(self):
|
||||
return min(self.state.send_query_delay, self.state.send_car_delay)
|
||||
|
||||
def extTransition(self, inputs):
|
||||
#print("ELAPSED: " + str(self.elapsed))
|
||||
#print("Got elapsed: " + str(self.elapsed))
|
||||
self.state.currentTime += self.elapsed
|
||||
self.state.send_query_delay -= self.elapsed
|
||||
self.state.send_car_delay -= self.elapsed
|
||||
queryAcks = inputs.get(self.Q_rack, [])
|
||||
for queryAck in queryAcks:
|
||||
if self.state.send_car_id == queryAck.ID and (self.state.sent < self.send_max):
|
||||
self.state.send_car_delay = queryAck.t_until_dep
|
||||
if queryAck.t_until_dep < 20000:
|
||||
self.state.sent += 1
|
||||
# Generate the next situation
|
||||
if self.state.sent < self.send_max:
|
||||
self.state.send_query_delay = self.randomGenerator.uniform(self.IAT_min, self.IAT_max)
|
||||
#self.state.send_query_id = int(self.randomGenerator.uniform(0, 100000))
|
||||
self.state.send_query_id += 1000000
|
||||
return self.state
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
return 0 if self.state.send_car_delay == float('inf') else 1
|
||||
|
||||
class Residence(Building):
|
||||
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):
|
||||
Building.__init__(self, True, district, path=path, name=name)
|
||||
|
||||
class CommercialState(object):
|
||||
def __init__(self, car):
|
||||
self.car = car
|
||||
|
||||
def __str__(self):
|
||||
return "CommercialState"
|
||||
|
||||
def copy(self):
|
||||
return CommercialState(self.car)
|
||||
|
||||
class Commercial(Building):
|
||||
def __init__(self, district, name="Commercial"):
|
||||
Building.__init__(self, False, district, name=name)
|
||||
self.state = CommercialState(None)
|
||||
self.toCollector = self.addOutPort(name="toCollector")
|
||||
|
||||
def extTransition(self, inputs):
|
||||
return CommercialState(inputs[self.entry][0])
|
||||
|
||||
def intTransition(self):
|
||||
return CommercialState(None)
|
||||
|
||||
def outputFnc(self):
|
||||
return {self.toCollector: [self.state.car]}
|
||||
|
||||
def timeAdvance(self):
|
||||
if self.state.car is None:
|
||||
return INFINITY
|
||||
else:
|
||||
return 0.0
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
return 0
|
||||
|
||||
class RoadSegmentState():
|
||||
def __init__(self):
|
||||
self.cars_present = []
|
||||
self.query_buffer = []
|
||||
self.deny_list = []
|
||||
self.reserved = False
|
||||
self.send_query_delay = INFINITY
|
||||
self.send_query_id = None
|
||||
self.send_ack_delay = INFINITY
|
||||
self.send_ack_id = None
|
||||
self.send_car_delay = INFINITY
|
||||
self.send_car_id = None
|
||||
self.last_car = None
|
||||
|
||||
def __eq__(self, other):
|
||||
if not (self.send_query_delay == other.send_query_delay and
|
||||
self.send_ack_delay == other.send_ack_delay and
|
||||
self.send_car_delay == other.send_car_delay and
|
||||
self.send_query_id == other.send_query_id and
|
||||
self.send_ack_id == other.send_ack_id and
|
||||
self.send_car_id == other.send_car_id and
|
||||
self.last_car == other.last_car and
|
||||
self.reserved == other.reserved):
|
||||
return False
|
||||
if self.query_buffer != other.query_buffer:
|
||||
return False
|
||||
if len(self.cars_present) != len(other.cars_present):
|
||||
return False
|
||||
for c1, c2 in zip(self.cars_present, other.cars_present):
|
||||
if c1 != c2:
|
||||
return False
|
||||
if len(self.deny_list) != len(other.deny_list):
|
||||
return False
|
||||
for q1, q2 in zip(self.deny_list, other.deny_list):
|
||||
if q1 != q2:
|
||||
return False
|
||||
return True
|
||||
|
||||
def copy(self):
|
||||
new = RoadSegmentState()
|
||||
new.cars_present = [c.copy() for c in self.cars_present]
|
||||
new.query_buffer = list(self.query_buffer)
|
||||
new.deny_list = [q.copy() for q in self.deny_list]
|
||||
new.reserved = self.reserved
|
||||
new.send_query_delay = self.send_query_delay
|
||||
new.send_query_id = self.send_query_id
|
||||
new.send_ack_delay = self.send_ack_delay
|
||||
new.send_ack_id = self.send_ack_id
|
||||
new.send_car_delay = self.send_car_delay
|
||||
new.send_car_id = self.send_car_id
|
||||
new.last_car = self.last_car
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
string = "Road segment: cars_present = ["
|
||||
for i in self.cars_present:
|
||||
string += str(i.ID) + ", "
|
||||
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)
|
||||
|
||||
class RoadSegment(AtomicDEVS):
|
||||
def __init__(self, district, load, l = 100.0, v_max = 18.0, observ_delay = 0.1, name = "RoadSegment"):
|
||||
AtomicDEVS.__init__(self, name)
|
||||
|
||||
# arguments
|
||||
self.l = float(l)
|
||||
self.v_max = v_max
|
||||
self.observ_delay = observ_delay
|
||||
self.district = district
|
||||
self.load = load
|
||||
|
||||
# in-ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
self.q_recv = self.addInPort(name="q_recv")
|
||||
self.car_in = self.addInPort(name="car_in")
|
||||
self.entries = self.addInPort(name="entries")
|
||||
self.q_rans_bs = self.addInPort(name="q_rans_bs")
|
||||
self.q_recv_bs = self.addInPort(name="q_recv_bs")
|
||||
# compatibility bindings...
|
||||
self.Q_recv = self.q_recv
|
||||
self.Q_rack = self.q_rans
|
||||
|
||||
# out-ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.car_out = self.addOutPort(name="car_out")
|
||||
self.exits = self.addOutPort(name="exits")
|
||||
|
||||
self.q_sans_bs = self.addOutPort(name="q_sans_bs")
|
||||
# compatibility bindings...
|
||||
self.Q_send = self.q_send
|
||||
self.Q_sack = self.q_sans
|
||||
|
||||
self.state = RoadSegmentState()
|
||||
|
||||
def extTransition(self, inputs):
|
||||
queries = inputs.get(self.Q_recv, [])
|
||||
queries.extend(inputs.get(self.q_recv_bs, []))
|
||||
cars = inputs.get(self.car_in, [])
|
||||
cars.extend(inputs.get(self.entries, []))
|
||||
acks = inputs.get(self.Q_rack, [])
|
||||
acks.extend(inputs.get(self.q_rans_bs, []))
|
||||
|
||||
self.state.send_query_delay -= self.elapsed
|
||||
self.state.send_ack_delay -= self.elapsed
|
||||
self.state.send_car_delay -= self.elapsed
|
||||
|
||||
for query in queries:
|
||||
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)):
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = query.ID
|
||||
self.state.reserved = True
|
||||
else:
|
||||
self.state.query_buffer.append(query.ID)
|
||||
self.state.deny_list.append(query)
|
||||
if self.state.send_ack_delay == INFINITY:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = query.ID
|
||||
self.state.last_car = query.ID
|
||||
for car in self.state.cars_present:
|
||||
car.remaining_x -= self.elapsed * car.v
|
||||
|
||||
for car in cars:
|
||||
self.state.last_car = None
|
||||
car.remaining_x = self.l
|
||||
self.state.cars_present.append(car)
|
||||
|
||||
if len(self.state.cars_present) != 1:
|
||||
for other_car in self.state.cars_present:
|
||||
other_car.v = 0
|
||||
self.state.send_query_delay = INFINITY
|
||||
self.state.send_ack_delay = INFINITY
|
||||
self.state.send_car_delay = INFINITY
|
||||
else:
|
||||
self.state.send_query_delay = 0
|
||||
self.state.send_query_id = car.ID
|
||||
if self.state.cars_present[-1].v == 0:
|
||||
t_to_dep = INFINITY
|
||||
else:
|
||||
t_to_dep = max(0, self.l/self.state.cars_present[-1].v)
|
||||
self.state.send_car_delay = t_to_dep
|
||||
self.state.send_car_id = car.ID
|
||||
|
||||
for ack in acks:
|
||||
if (len(self.state.cars_present) == 1) and (ack.ID == self.state.cars_present[0].ID):
|
||||
car = self.state.cars_present[0]
|
||||
t_no_col = ack.t_until_dep
|
||||
v_old = car.v
|
||||
v_pref = car.v_pref
|
||||
remaining_x = car.remaining_x
|
||||
|
||||
if t_no_col + 1 == t_no_col:
|
||||
v_new = 0
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
v_ideal = remaining_x / max(t_no_col, remaining_x / min(v_pref, self.v_max))
|
||||
diff = v_ideal - v_old
|
||||
if diff < 0:
|
||||
if -diff > car.dv_neg_max:
|
||||
diff = -car.dv_neg_max
|
||||
elif diff > 0:
|
||||
if diff > car.dv_pos_max:
|
||||
diff = car.dv_pos_max
|
||||
v_new = v_old + diff
|
||||
if v_new == 0:
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
t_until_dep = car.remaining_x / v_new
|
||||
|
||||
car.v = v_new
|
||||
|
||||
t_until_dep = max(0, t_until_dep)
|
||||
if t_until_dep > self.state.send_car_delay and self.state.last_car is not None:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = self.state.last_car
|
||||
self.state.send_car_delay = t_until_dep
|
||||
self.state.send_car_id = ack.ID
|
||||
|
||||
if t_until_dep == INFINITY:
|
||||
self.state.send_query_id = ack.ID
|
||||
else:
|
||||
self.state.send_query_id = None
|
||||
self.state.send_query_delay = INFINITY
|
||||
return self.state
|
||||
|
||||
def intTransition(self):
|
||||
for _ in range(self.load):
|
||||
pass
|
||||
mintime = self.mintime()
|
||||
self.state.send_query_delay -= mintime
|
||||
self.state.send_ack_delay -= mintime
|
||||
self.state.send_car_delay -= mintime
|
||||
if self.state.send_ack_delay == 0:
|
||||
self.state.send_ack_delay = INFINITY
|
||||
self.state.send_ack_id = None
|
||||
|
||||
elif self.state.send_query_delay == 0:
|
||||
# Just sent a query, now deny all other queries and wait until the current car has left
|
||||
self.state.send_query_delay = INFINITY
|
||||
self.state.send_query_id = None
|
||||
elif self.state.send_car_delay == 0:
|
||||
self.state.cars_present = []
|
||||
self.state.send_car_delay = INFINITY
|
||||
self.state.send_car_id = None
|
||||
|
||||
# A car has left, so we can answer to the first other query we received
|
||||
if len(self.state.query_buffer) != 0:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
#print("Setting %s in %s" % (self.state.query_buffer, self.name))
|
||||
self.state.send_ack_id = self.state.query_buffer.pop()
|
||||
else:
|
||||
# No car is waiting for this segment, so 'unreserve' it
|
||||
self.state.reserved = False
|
||||
if self.state.send_ack_id == None and len(self.state.deny_list) > 0:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
#print("Denylist = %s in %s" % (self.state.deny_list, self.name))
|
||||
self.state.send_ack_id = self.state.deny_list[0].ID
|
||||
self.state.deny_list = self.state.deny_list[1:]
|
||||
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
outputs = {}
|
||||
mintime = self.mintime()
|
||||
if self.state.send_ack_delay == mintime:
|
||||
ackID = self.state.send_ack_id
|
||||
if len(self.state.cars_present) == 0:
|
||||
t_until_dep = 0
|
||||
elif (self.state.cars_present[0].v) == 0:
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
t_until_dep = self.l / self.state.cars_present[0].v
|
||||
ack = QueryAck(ackID, t_until_dep)
|
||||
outputs[self.Q_sack] = [ack]
|
||||
outputs[self.q_sans_bs] = [ack]
|
||||
elif self.state.send_query_delay == mintime:
|
||||
query = Query(self.state.send_query_id)
|
||||
if self.state.cars_present[0].path != []:
|
||||
query.direction = self.state.cars_present[0].path[0]
|
||||
outputs[self.Q_send] = [query]
|
||||
elif self.state.send_car_delay == mintime:
|
||||
car = self.state.cars_present[0]
|
||||
car.distance_travelled += self.l
|
||||
if len(car.path) == 0:
|
||||
outputs[self.exits] = [car]
|
||||
else:
|
||||
outputs[self.car_out] = [car]
|
||||
return outputs
|
||||
|
||||
def mintime(self):
|
||||
return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
|
||||
def timeAdvance(self):
|
||||
#return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
delay = min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
# Take care of floating point errors
|
||||
return max(delay, 0)
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
# If a car has collided, no activity is here
|
||||
return 1 if len(self.state.cars_present) == 1 else 0
|
||||
|
||||
class Road(CoupledDEVS):
|
||||
def __init__(self, district, load, name="Road", segments=5):
|
||||
CoupledDEVS.__init__(self, name)
|
||||
self.segment = []
|
||||
for i in range(segments):
|
||||
self.segment.append(self.addSubModel(RoadSegment(load=load, district=district, name=(name + "_" + str(i)))))
|
||||
|
||||
# in-ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
self.q_recv = self.addInPort(name="q_recv")
|
||||
self.car_in = self.addInPort(name="car_in")
|
||||
self.entries = self.addInPort(name="entries")
|
||||
self.q_rans_bs = self.addInPort(name="q_rans_bs")
|
||||
self.q_recv_bs = self.addInPort(name="q_recv_bs")
|
||||
|
||||
# out-ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.car_out = self.addOutPort(name="car_out")
|
||||
self.exits = self.addOutPort(name="exits")
|
||||
self.q_sans_bs = self.addOutPort(name="q_sans_bs")
|
||||
|
||||
self.connectPorts(self.q_rans, self.segment[-1].q_rans)
|
||||
self.connectPorts(self.q_recv, self.segment[0].q_recv)
|
||||
self.connectPorts(self.car_in, self.segment[0].car_in)
|
||||
self.connectPorts(self.entries, self.segment[0].entries)
|
||||
self.connectPorts(self.q_rans_bs, self.segment[0].q_rans_bs)
|
||||
self.connectPorts(self.q_recv_bs, self.segment[0].q_recv_bs)
|
||||
|
||||
self.connectPorts(self.segment[0].q_sans, self.q_sans)
|
||||
self.connectPorts(self.segment[-1].q_send, self.q_send)
|
||||
self.connectPorts(self.segment[-1].car_out, self.car_out)
|
||||
self.connectPorts(self.segment[0].exits, self.exits)
|
||||
self.connectPorts(self.segment[0].q_sans_bs, self.q_sans_bs)
|
||||
|
||||
for i in range(segments):
|
||||
if i == 0:
|
||||
continue
|
||||
self.connectPorts(self.segment[i].q_sans, self.segment[i-1].q_rans)
|
||||
self.connectPorts(self.segment[i-1].q_send, self.segment[i].q_recv)
|
||||
self.connectPorts(self.segment[i-1].car_out, self.segment[i].car_in)
|
||||
|
||||
class IntersectionState():
|
||||
def __init__(self, switch_signal):
|
||||
self.send_query = []
|
||||
self.send_ack = []
|
||||
self.send_car = []
|
||||
self.queued_queries = []
|
||||
self.id_locations = [None, None, None, None]
|
||||
self.block = vertical
|
||||
self.switch_signal = switch_signal
|
||||
self.ackDir = {}
|
||||
|
||||
def __str__(self):
|
||||
return "ISECT blocking " + str(self.block)
|
||||
return "Intersection: send_query = " + str(self.send_query) + ", send_ack = " + str(self.send_ack) + ", send_car = " + str(self.send_car) + ", block = " + str(self.block)
|
||||
|
||||
def copy(self):
|
||||
new = IntersectionState(self.switch_signal)
|
||||
new.send_query = [q.copy() for q in self.send_query]
|
||||
new.send_ack = [a.copy() for a in self.send_ack]
|
||||
new.send_car = [c.copy() for c in self.send_car]
|
||||
new.queued_queries = [q.copy() for q in self.queued_queries]
|
||||
new.id_locations = list(self.id_locations)
|
||||
new.block = self.block
|
||||
new.switch_signal = self.switch_signal
|
||||
new.ackDir = dict(self.ackDir)
|
||||
return new
|
||||
|
||||
class Intersection(AtomicDEVS):
|
||||
def __init__(self, district, name="Intersection", switch_signal = 30):
|
||||
AtomicDEVS.__init__(self, name=name)
|
||||
self.state = IntersectionState(switch_signal)
|
||||
self.switch_signal_delay = switch_signal
|
||||
self.district = district
|
||||
|
||||
self.q_send = []
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_n"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_e"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_s"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_w"))
|
||||
|
||||
self.q_rans = []
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_n"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_e"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_s"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_w"))
|
||||
|
||||
self.q_recv = []
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_n"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_e"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_s"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_w"))
|
||||
|
||||
self.q_sans = []
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_n"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_e"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_s"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_w"))
|
||||
|
||||
self.car_in = []
|
||||
self.car_in.append(self.addInPort(name="car_in_from_n"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_e"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_s"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_w"))
|
||||
|
||||
self.car_out = []
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_n"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_e"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_s"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_w"))
|
||||
|
||||
def intTransition(self):
|
||||
self.state.switch_signal -= self.timeAdvance()
|
||||
if self.state.switch_signal <= 1e-6:
|
||||
# We switched our traffic lights
|
||||
self.state.switch_signal = self.switch_signal_delay
|
||||
self.state.queued_queries = []
|
||||
self.state.block = vertical if self.state.block == horizontal else horizontal
|
||||
|
||||
for loc, car_id in enumerate(self.state.id_locations):
|
||||
# Notify all cars that got 'green' that they should not continue
|
||||
if car_id is None:
|
||||
continue
|
||||
try:
|
||||
if str(loc) in self.state.block:
|
||||
query = Query(car_id)
|
||||
query.direction = int_to_dir[self.state.ackDir[car_id]]
|
||||
self.state.queued_queries.append(query)
|
||||
except KeyError:
|
||||
pass
|
||||
self.state.send_car = []
|
||||
self.state.send_query = []
|
||||
self.state.send_ack = []
|
||||
return self.state
|
||||
|
||||
def extTransition(self, inputs):
|
||||
# Simple forwarding of all messages
|
||||
# Unless the direction in which it is going is blocked
|
||||
self.state.switch_signal -= self.elapsed
|
||||
for direction in range(4):
|
||||
blocked = str(direction) in self.state.block
|
||||
for car in inputs.get(self.car_in[direction], []):
|
||||
self.state.send_car.append(car)
|
||||
# Got a car, so remove its ID location entry
|
||||
try:
|
||||
del self.state.ackDir[car.ID]
|
||||
self.state.id_locations[self.state.id_locations.index(car.ID)] = None
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
self.state.queued_queries = [query for query in self.state.queued_queries if query.ID != car.ID]
|
||||
for query in inputs.get(self.q_recv[direction], []):
|
||||
self.state.id_locations[direction] = query.ID
|
||||
self.state.ackDir[query.ID] = dir_to_int[query.direction]
|
||||
if blocked:
|
||||
self.state.send_ack.append(QueryAck(query.ID, INFINITY))
|
||||
self.state.queued_queries.append(query)
|
||||
else:
|
||||
self.state.send_query.append(query)
|
||||
for ack in inputs.get(self.q_rans[direction], []):
|
||||
self.state.ackDir[ack.ID] = direction
|
||||
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)):
|
||||
try:
|
||||
self.state.id_locations.index(ack.ID)
|
||||
t_until_dep = INFINITY
|
||||
nquery = Query(ack.ID)
|
||||
nquery.direction = int_to_dir[direction]
|
||||
self.state.queued_queries.append(nquery)
|
||||
except ValueError:
|
||||
continue
|
||||
else:
|
||||
t_until_dep = ack.t_until_dep
|
||||
self.state.send_ack.append(QueryAck(ack.ID, t_until_dep))
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
# Can simply overwrite, as multiple calls to the same destination is impossible
|
||||
toSend = {}
|
||||
new_block = vertical if self.state.block == horizontal else horizontal
|
||||
if self.state.switch_signal == self.timeAdvance():
|
||||
# We switch our traffic lights
|
||||
# Resend all queries for those that are waiting
|
||||
for query in self.state.queued_queries:
|
||||
if str(self.state.id_locations.index(query.ID)) not in new_block:
|
||||
toSend[self.q_send[dir_to_int[query.direction]]] = [query]
|
||||
for loc, car_id in enumerate(self.state.id_locations):
|
||||
# Notify all cars that got 'green' that they should not continue
|
||||
if car_id is None:
|
||||
continue
|
||||
if str(loc) in new_block:
|
||||
toSend[self.q_sans[loc]] = [QueryAck(car_id, INFINITY)]
|
||||
else:
|
||||
try:
|
||||
query = Query(car_id)
|
||||
query.direction = int_to_dir[self.state.ackDir[car_id]]
|
||||
toSend[self.q_send[self.state.ackDir[car_id]]] = [query]
|
||||
except KeyError:
|
||||
pass
|
||||
# We might have some messages to forward too
|
||||
for car in self.state.send_car:
|
||||
dest = car.path.pop(0)
|
||||
toSend[self.car_out[dir_to_int[dest]]] = [car]
|
||||
for query in self.state.send_query:
|
||||
toSend[self.q_send[dir_to_int[query.direction]]] = [query]
|
||||
for ack in self.state.send_ack:
|
||||
# Broadcast for now
|
||||
try:
|
||||
toSend[self.q_sans[self.state.id_locations.index(ack.ID)]] = [ack]
|
||||
except ValueError:
|
||||
pass
|
||||
return toSend
|
||||
|
||||
def timeAdvance(self):
|
||||
if len(self.state.send_car) + len(self.state.send_query) + len(self.state.send_ack) > 0:
|
||||
return 0.0
|
||||
else:
|
||||
return max(self.state.switch_signal, 0.0)
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
return len(self.state.send_car)
|
||||
|
||||
class CollectorState(object):
|
||||
def __init__(self):
|
||||
self.cars = []
|
||||
|
||||
def copy(self):
|
||||
new = CollectorState()
|
||||
new.cars = list(self.cars)
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
## Print your statistics here!
|
||||
s = "All cars collected:"
|
||||
for car in self.cars:
|
||||
s += "\n\t\t\t%s" % car
|
||||
return s
|
||||
|
||||
class Collector(AtomicDEVS):
|
||||
def __init__(self):
|
||||
AtomicDEVS.__init__(self, "Collector")
|
||||
self.car_in = self.addInPort("car_in")
|
||||
self.state = CollectorState()
|
||||
self.district = 0
|
||||
|
||||
def extTransition(self, inputs):
|
||||
self.state.cars.extend(inputs[self.car_in])
|
||||
return self.state
|
||||
|
||||
def preActivityCalculation(self):
|
||||
return None
|
||||
|
||||
def postActivityCalculation(self, _):
|
||||
return 0
|
||||
10847
models/dist_activity_citylayout/generated_city.py
Normal file
10847
models/dist_activity_citylayout/generated_city.py
Normal file
File diff suppressed because it is too large
Load diff
8
models/dist_activity_citylayout/local_3/results_AT
Normal file
8
models/dist_activity_citylayout/local_3/results_AT
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 73
|
||||
10000 83
|
||||
15000 95
|
||||
20000 118
|
||||
25000 153
|
||||
30000 187
|
||||
35000 241
|
||||
40000 273
|
||||
8
models/dist_activity_citylayout/local_3/results_CA
Normal file
8
models/dist_activity_citylayout/local_3/results_CA
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 74
|
||||
10000 85
|
||||
15000 102
|
||||
20000 120
|
||||
25000 145
|
||||
30000 178
|
||||
35000 211
|
||||
40000 251
|
||||
8
models/dist_activity_citylayout/local_3/results_CACR
Normal file
8
models/dist_activity_citylayout/local_3/results_CACR
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 76
|
||||
10000 85
|
||||
15000 98
|
||||
20000 118
|
||||
25000 141
|
||||
30000 173
|
||||
35000 214
|
||||
40000 251
|
||||
8
models/dist_activity_citylayout/local_3/results_NO
Normal file
8
models/dist_activity_citylayout/local_3/results_NO
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 77
|
||||
10000 91
|
||||
15000 107
|
||||
20000 128
|
||||
25000 156
|
||||
30000 188
|
||||
35000 223
|
||||
40000 266
|
||||
|
|
@ -0,0 +1,741 @@
|
|||
import sys
|
||||
sys.path.append("../../../src/")
|
||||
from infinity import *
|
||||
from DEVS import *
|
||||
import random
|
||||
|
||||
north = 0
|
||||
east = 1
|
||||
south = 2
|
||||
west = 3
|
||||
vertical = "02"
|
||||
horizontal = "13"
|
||||
dir_to_int = {'n': north, 'e': east, 's': south, 'w': west}
|
||||
int_to_dir = {north: 'n', east: 'e', south: 's', west: 'w'}
|
||||
|
||||
class Car:
|
||||
def __init__(self, ID, v, v_pref, dv_pos_max, dv_neg_max, departure_time):
|
||||
self.ID = ID
|
||||
self.v_pref = v_pref
|
||||
self.dv_pos_max = dv_pos_max
|
||||
self.dv_neg_max = dv_neg_max
|
||||
self.departure_time = departure_time
|
||||
self.distance_travelled = 0
|
||||
self.remaining_x = 0
|
||||
self.v = v
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and
|
||||
self.v_pref == other.v_pref and
|
||||
self.dv_pos_max == other.dv_pos_max and
|
||||
self.dv_neg_max == other.dv_neg_max and
|
||||
self.departure_time == other.departure_time and
|
||||
self.distance_travelled == other.distance_travelled and
|
||||
self.remaining_x == other.remaining_x and
|
||||
self.v == other.v)
|
||||
|
||||
def __str__(self):
|
||||
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)
|
||||
|
||||
def copy(self):
|
||||
car = Car(self.ID, self.v, self.v_pref, self.dv_pos_max, self.dv_neg_max, self.departure_time)
|
||||
car.distance_travelled = self.distance_travelled
|
||||
car.remaining_x = self.remaining_x
|
||||
car.path = list(self.path)
|
||||
return car
|
||||
|
||||
class Query:
|
||||
def __init__(self, ID):
|
||||
self.ID = ID
|
||||
self.direction = ''
|
||||
|
||||
def __str__(self):
|
||||
return "Query: ID = " + str(self.ID)
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and self.direction == other.direction)
|
||||
|
||||
def copy(self):
|
||||
query = Query(self.ID)
|
||||
query.direction = self.direction
|
||||
return query
|
||||
|
||||
class QueryAck:
|
||||
def __init__(self, ID, t_until_dep):
|
||||
self.ID = ID
|
||||
self.t_until_dep = t_until_dep
|
||||
|
||||
def __str__(self):
|
||||
return "Query Ack: ID = " + str(self.ID) + ", t_until_dep = %.3f" % self.t_until_dep
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.ID == other.ID and self.t_until_dep == other.t_until_dep)
|
||||
|
||||
def copy(self):
|
||||
return QueryAck(self.ID, self.t_until_dep)
|
||||
|
||||
class BuildingState:
|
||||
def __init__(self, IAT_min, IAT_max, path, name):
|
||||
self.currentTime = 0
|
||||
from randomGenerator import RandomGenerator
|
||||
seed = random.random()
|
||||
self.randomGenerator = RandomGenerator(seed)
|
||||
self.send_query_delay = self.randomGenerator.uniform(IAT_min, IAT_max)
|
||||
|
||||
self.send_car_delay = INFINITY
|
||||
self.path = path
|
||||
if path == []:
|
||||
self.send_query_delay = INFINITY
|
||||
|
||||
self.name = name
|
||||
self.send_query_id = int(name.split("_", 1)[1].split("_")[0]) * 1000 + int(name.split("_", 1)[1].split("_")[1])
|
||||
self.send_car_id = self.send_query_id
|
||||
self.next_v_pref = 0
|
||||
self.sent = 0
|
||||
|
||||
def copy(self):
|
||||
new = BuildingState(0, 0, list(self.path), self.name)
|
||||
new.currentTime = self.currentTime
|
||||
new.send_query_delay = self.send_query_delay
|
||||
new.send_car_delay = self.send_car_delay
|
||||
new.send_query_id = self.send_query_id
|
||||
new.send_car_id = self.send_car_id
|
||||
new.next_v_pref = self.next_v_pref
|
||||
new.randomGenerator = self.randomGenerator.copy()
|
||||
new.sent = self.sent
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
if self.path != []:
|
||||
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)
|
||||
else:
|
||||
return "Commercial: waiting..."
|
||||
|
||||
class Building(AtomicDEVS):
|
||||
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"):
|
||||
# parent class constructor
|
||||
AtomicDEVS.__init__(self, name)
|
||||
|
||||
# copy of arguments
|
||||
self.IAT_min = IAT_min
|
||||
self.IAT_max = IAT_max
|
||||
self.v_pref_min = v_pref_min
|
||||
self.v_pref_max = v_pref_max
|
||||
self.dv_pos_max = dv_pos_max
|
||||
self.dv_neg_max = dv_neg_max
|
||||
|
||||
# output ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.exit = self.addOutPort(name="exit")
|
||||
self.Q_send = self.q_send
|
||||
self.car_out = self.exit
|
||||
|
||||
# input ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
#self.q_recv = self.addInPort(name="q_recv")
|
||||
self.Q_rack = self.q_rans
|
||||
self.entry = self.addInPort(name="entry")
|
||||
|
||||
# set the state
|
||||
self.state = BuildingState(IAT_min, IAT_max, path, name)
|
||||
self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
|
||||
self.send_max = 1
|
||||
|
||||
self.district = district
|
||||
|
||||
def intTransition(self):
|
||||
mintime = self.timeAdvance()
|
||||
#print("Got mintime: " + str(mintime))
|
||||
self.state.currentTime += mintime
|
||||
|
||||
self.state.send_query_delay -= mintime
|
||||
self.state.send_car_delay -= mintime
|
||||
|
||||
if self.state.send_car_delay == 0:
|
||||
self.state.send_car_delay = INFINITY
|
||||
self.state.send_car_id = self.state.send_query_id
|
||||
self.state.next_v_pref = self.state.randomGenerator.uniform(self.v_pref_min, self.v_pref_max)
|
||||
elif self.state.send_query_delay == 0:
|
||||
self.state.send_query_delay = INFINITY
|
||||
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
mintime = self.timeAdvance()
|
||||
#print("Got mintime: " + str(mintime))
|
||||
currentTime = self.state.currentTime + self.timeAdvance()
|
||||
outputs = {}
|
||||
|
||||
if self.state.send_car_delay == mintime:
|
||||
v_pref = self.state.next_v_pref
|
||||
car = Car(self.state.send_car_id, 0, v_pref, self.dv_pos_max, self.dv_neg_max, currentTime)
|
||||
car.path = self.state.path
|
||||
#self.poke(self.car_out, car)
|
||||
outputs[self.car_out] = [car]
|
||||
elif self.state.send_query_delay == mintime:
|
||||
query = Query(self.state.send_query_id)
|
||||
#self.poke(self.Q_send, query)
|
||||
outputs[self.Q_send] = [query]
|
||||
return outputs
|
||||
|
||||
def timeAdvance(self):
|
||||
return min(self.state.send_query_delay, self.state.send_car_delay)
|
||||
|
||||
def extTransition(self, inputs):
|
||||
#print("ELAPSED: " + str(self.elapsed))
|
||||
#print("Got elapsed: " + str(self.elapsed))
|
||||
self.state.currentTime += self.elapsed
|
||||
self.state.send_query_delay -= self.elapsed
|
||||
self.state.send_car_delay -= self.elapsed
|
||||
queryAcks = inputs.get(self.Q_rack, [])
|
||||
for queryAck in queryAcks:
|
||||
if self.state.send_car_id == queryAck.ID and (self.state.sent < self.send_max):
|
||||
self.state.send_car_delay = queryAck.t_until_dep
|
||||
if queryAck.t_until_dep < 20000:
|
||||
self.state.sent += 1
|
||||
# Generate the next situation
|
||||
if self.state.sent < self.send_max:
|
||||
self.state.send_query_delay = self.randomGenerator.uniform(self.IAT_min, self.IAT_max)
|
||||
#self.state.send_query_id = int(self.randomGenerator.uniform(0, 100000))
|
||||
self.state.send_query_id += 1000000
|
||||
return self.state
|
||||
|
||||
class Residence(Building):
|
||||
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):
|
||||
Building.__init__(self, True, district, path=path, name=name)
|
||||
|
||||
class CommercialState(object):
|
||||
def __init__(self, car):
|
||||
self.car = car
|
||||
|
||||
def __str__(self):
|
||||
return "CommercialState"
|
||||
|
||||
def copy(self):
|
||||
return CommercialState(self.car)
|
||||
|
||||
class Commercial(Building):
|
||||
def __init__(self, district, name="Commercial"):
|
||||
Building.__init__(self, False, district, name=name)
|
||||
self.state = CommercialState(None)
|
||||
self.toCollector = self.addOutPort(name="toCollector")
|
||||
|
||||
def extTransition(self, inputs):
|
||||
return CommercialState(inputs[self.entry][0])
|
||||
|
||||
def intTransition(self):
|
||||
return CommercialState(None)
|
||||
|
||||
def outputFnc(self):
|
||||
return {self.toCollector: [self.state.car]}
|
||||
|
||||
def timeAdvance(self):
|
||||
if self.state.car is None:
|
||||
return INFINITY
|
||||
else:
|
||||
return 0.0
|
||||
|
||||
class RoadSegmentState():
|
||||
def __init__(self):
|
||||
self.cars_present = []
|
||||
self.query_buffer = []
|
||||
self.deny_list = []
|
||||
self.reserved = False
|
||||
self.send_query_delay = INFINITY
|
||||
self.send_query_id = None
|
||||
self.send_ack_delay = INFINITY
|
||||
self.send_ack_id = None
|
||||
self.send_car_delay = INFINITY
|
||||
self.send_car_id = None
|
||||
self.last_car = None
|
||||
|
||||
def __eq__(self, other):
|
||||
if self.query_buffer != other.query_buffer:
|
||||
return False
|
||||
if not (self.send_query_delay == other.send_query_delay and
|
||||
self.send_ack_delay == other.send_ack_delay and
|
||||
self.send_car_delay == other.send_car_delay and
|
||||
self.send_query_id == other.send_query_id and
|
||||
self.send_ack_id == other.send_ack_id and
|
||||
self.send_car_id == other.send_car_id):
|
||||
return False
|
||||
if self.reserved != other.reserved:
|
||||
return False
|
||||
if len(self.cars_present) != len(other.cars_present):
|
||||
return False
|
||||
for c1, c2 in zip(self.cars_present, other.cars_present):
|
||||
if c1 != c2:
|
||||
return False
|
||||
if self.last_car != other.last_car:
|
||||
return False
|
||||
if len(self.deny_list) != len(other.deny_list):
|
||||
return False
|
||||
for q1, q2 in zip(self.deny_list, other.deny_list):
|
||||
if q1 != q2:
|
||||
return False
|
||||
return True
|
||||
|
||||
def copy(self):
|
||||
new = RoadSegmentState()
|
||||
new.cars_present = [c.copy() for c in self.cars_present]
|
||||
new.deny_list = [q.copy() for q in self.deny_list]
|
||||
new.query_buffer = list(self.query_buffer)
|
||||
new.reserved = self.reserved
|
||||
new.send_query_delay = self.send_query_delay
|
||||
new.send_query_id = self.send_query_id
|
||||
new.send_ack_delay = self.send_ack_delay
|
||||
new.send_ack_id = self.send_ack_id
|
||||
new.send_car_delay = self.send_car_delay
|
||||
new.send_car_id = self.send_car_id
|
||||
new.last_car = self.last_car
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
string = "Road segment: cars_present = ["
|
||||
for i in self.cars_present:
|
||||
string += str(i.ID) + ", "
|
||||
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)
|
||||
|
||||
class RoadSegment(AtomicDEVS):
|
||||
def __init__(self, district, load, l = 100.0, v_max = 18.0, observ_delay = 0.1, name = "RoadSegment"):
|
||||
AtomicDEVS.__init__(self, name)
|
||||
|
||||
# arguments
|
||||
self.l = float(l)
|
||||
self.v_max = v_max
|
||||
self.observ_delay = observ_delay
|
||||
self.district = district
|
||||
self.load = load
|
||||
|
||||
# in-ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
self.q_recv = self.addInPort(name="q_recv")
|
||||
self.car_in = self.addInPort(name="car_in")
|
||||
self.entries = self.addInPort(name="entries")
|
||||
self.q_rans_bs = self.addInPort(name="q_rans_bs")
|
||||
self.q_recv_bs = self.addInPort(name="q_recv_bs")
|
||||
# compatibility bindings...
|
||||
self.Q_recv = self.q_recv
|
||||
self.Q_rack = self.q_rans
|
||||
|
||||
# out-ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.car_out = self.addOutPort(name="car_out")
|
||||
self.exits = self.addOutPort(name="exits")
|
||||
|
||||
self.q_sans_bs = self.addOutPort(name="q_sans_bs")
|
||||
# compatibility bindings...
|
||||
self.Q_send = self.q_send
|
||||
self.Q_sack = self.q_sans
|
||||
|
||||
self.state = RoadSegmentState()
|
||||
|
||||
def extTransition(self, inputs):
|
||||
queries = inputs.get(self.Q_recv, [])
|
||||
queries.extend(inputs.get(self.q_recv_bs, []))
|
||||
cars = inputs.get(self.car_in, [])
|
||||
cars.extend(inputs.get(self.entries, []))
|
||||
acks = inputs.get(self.Q_rack, [])
|
||||
acks.extend(inputs.get(self.q_rans_bs, []))
|
||||
|
||||
self.state.send_query_delay -= self.elapsed
|
||||
self.state.send_ack_delay -= self.elapsed
|
||||
self.state.send_car_delay -= self.elapsed
|
||||
|
||||
for query in queries:
|
||||
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)):
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = query.ID
|
||||
self.state.reserved = True
|
||||
else:
|
||||
self.state.query_buffer.append(query.ID)
|
||||
self.state.deny_list.append(query)
|
||||
if self.state.send_ack_delay == INFINITY:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = query.ID
|
||||
self.state.last_car = query.ID
|
||||
for car in self.state.cars_present:
|
||||
car.remaining_x -= self.elapsed * car.v
|
||||
|
||||
for car in cars:
|
||||
self.state.last_car = None
|
||||
car.remaining_x = self.l
|
||||
self.state.cars_present.append(car)
|
||||
|
||||
if len(self.state.cars_present) != 1:
|
||||
for other_car in self.state.cars_present:
|
||||
other_car.v = 0
|
||||
self.state.send_query_delay = INFINITY
|
||||
self.state.send_ack_delay = INFINITY
|
||||
self.state.send_car_delay = INFINITY
|
||||
else:
|
||||
self.state.send_query_delay = 0
|
||||
self.state.send_query_id = car.ID
|
||||
if self.state.cars_present[-1].v == 0:
|
||||
t_to_dep = INFINITY
|
||||
else:
|
||||
t_to_dep = max(0, self.l/self.state.cars_present[-1].v)
|
||||
self.state.send_car_delay = t_to_dep
|
||||
self.state.send_car_id = car.ID
|
||||
|
||||
for ack in acks:
|
||||
if (len(self.state.cars_present) == 1) and (ack.ID == self.state.cars_present[0].ID):
|
||||
car = self.state.cars_present[0]
|
||||
t_no_col = ack.t_until_dep
|
||||
v_old = car.v
|
||||
v_pref = car.v_pref
|
||||
remaining_x = car.remaining_x
|
||||
|
||||
if t_no_col + 1 == t_no_col:
|
||||
v_new = 0
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
v_ideal = remaining_x / max(t_no_col, remaining_x / min(v_pref, self.v_max))
|
||||
diff = v_ideal - v_old
|
||||
if diff < 0:
|
||||
if -diff > car.dv_neg_max:
|
||||
diff = -car.dv_neg_max
|
||||
elif diff > 0:
|
||||
if diff > car.dv_pos_max:
|
||||
diff = car.dv_pos_max
|
||||
v_new = v_old + diff
|
||||
if v_new == 0:
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
t_until_dep = car.remaining_x / v_new
|
||||
|
||||
car.v = v_new
|
||||
|
||||
t_until_dep = max(0, t_until_dep)
|
||||
if t_until_dep > self.state.send_car_delay and self.state.last_car is not None:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
self.state.send_ack_id = self.state.last_car
|
||||
self.state.send_car_delay = t_until_dep
|
||||
self.state.send_car_id = ack.ID
|
||||
|
||||
if t_until_dep == INFINITY:
|
||||
self.state.send_query_id = ack.ID
|
||||
else:
|
||||
self.state.send_query_id = None
|
||||
self.state.send_query_delay = INFINITY
|
||||
return self.state
|
||||
|
||||
def intTransition(self):
|
||||
for _ in range(self.load):
|
||||
pass
|
||||
mintime = self.mintime()
|
||||
self.state.send_query_delay -= mintime
|
||||
self.state.send_ack_delay -= mintime
|
||||
self.state.send_car_delay -= mintime
|
||||
if self.state.send_ack_delay == 0:
|
||||
self.state.send_ack_delay = INFINITY
|
||||
self.state.send_ack_id = None
|
||||
|
||||
elif self.state.send_query_delay == 0:
|
||||
# Just sent a query, now deny all other queries and wait until the current car has left
|
||||
self.state.send_query_delay = INFINITY
|
||||
self.state.send_query_id = None
|
||||
elif self.state.send_car_delay == 0:
|
||||
self.state.cars_present = []
|
||||
self.state.send_car_delay = INFINITY
|
||||
self.state.send_car_id = None
|
||||
|
||||
# A car has left, so we can answer to the first other query we received
|
||||
if len(self.state.query_buffer) != 0:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
#print("Setting %s in %s" % (self.state.query_buffer, self.name))
|
||||
self.state.send_ack_id = self.state.query_buffer.pop()
|
||||
else:
|
||||
# No car is waiting for this segment, so 'unreserve' it
|
||||
self.state.reserved = False
|
||||
if self.state.send_ack_id == None and len(self.state.deny_list) > 0:
|
||||
self.state.send_ack_delay = self.observ_delay
|
||||
#print("Denylist = %s in %s" % (self.state.deny_list, self.name))
|
||||
self.state.send_ack_id = self.state.deny_list[0].ID
|
||||
self.state.deny_list = self.state.deny_list[1:]
|
||||
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
outputs = {}
|
||||
mintime = self.mintime()
|
||||
if self.state.send_ack_delay == mintime:
|
||||
ackID = self.state.send_ack_id
|
||||
if len(self.state.cars_present) == 0:
|
||||
t_until_dep = 0
|
||||
elif (self.state.cars_present[0].v) == 0:
|
||||
t_until_dep = INFINITY
|
||||
else:
|
||||
t_until_dep = self.l / self.state.cars_present[0].v
|
||||
ack = QueryAck(ackID, t_until_dep)
|
||||
outputs[self.Q_sack] = [ack]
|
||||
outputs[self.q_sans_bs] = [ack]
|
||||
elif self.state.send_query_delay == mintime:
|
||||
query = Query(self.state.send_query_id)
|
||||
if self.state.cars_present[0].path != []:
|
||||
query.direction = self.state.cars_present[0].path[0]
|
||||
outputs[self.Q_send] = [query]
|
||||
elif self.state.send_car_delay == mintime:
|
||||
car = self.state.cars_present[0]
|
||||
car.distance_travelled += self.l
|
||||
if len(car.path) == 0:
|
||||
outputs[self.exits] = [car]
|
||||
else:
|
||||
outputs[self.car_out] = [car]
|
||||
return outputs
|
||||
|
||||
def mintime(self):
|
||||
return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
|
||||
def timeAdvance(self):
|
||||
#return min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
delay = min(self.state.send_query_delay, self.state.send_ack_delay, self.state.send_car_delay)
|
||||
# Take care of floating point errors
|
||||
return max(delay, 0)
|
||||
|
||||
class Road(CoupledDEVS):
|
||||
def __init__(self, district, load, name="Road", segments=5):
|
||||
CoupledDEVS.__init__(self, name)
|
||||
self.segment = []
|
||||
for i in range(segments):
|
||||
self.segment.append(self.addSubModel(RoadSegment(load=load, district=district, name=(name + "_" + str(i)))))
|
||||
|
||||
# in-ports
|
||||
self.q_rans = self.addInPort(name="q_rans")
|
||||
self.q_recv = self.addInPort(name="q_recv")
|
||||
self.car_in = self.addInPort(name="car_in")
|
||||
self.entries = self.addInPort(name="entries")
|
||||
self.q_rans_bs = self.addInPort(name="q_rans_bs")
|
||||
self.q_recv_bs = self.addInPort(name="q_recv_bs")
|
||||
|
||||
# out-ports
|
||||
self.q_sans = self.addOutPort(name="q_sans")
|
||||
self.q_send = self.addOutPort(name="q_send")
|
||||
self.car_out = self.addOutPort(name="car_out")
|
||||
self.exits = self.addOutPort(name="exits")
|
||||
self.q_sans_bs = self.addOutPort(name="q_sans_bs")
|
||||
|
||||
self.connectPorts(self.q_rans, self.segment[-1].q_rans)
|
||||
self.connectPorts(self.q_recv, self.segment[0].q_recv)
|
||||
self.connectPorts(self.car_in, self.segment[0].car_in)
|
||||
self.connectPorts(self.entries, self.segment[0].entries)
|
||||
self.connectPorts(self.q_rans_bs, self.segment[0].q_rans_bs)
|
||||
self.connectPorts(self.q_recv_bs, self.segment[0].q_recv_bs)
|
||||
|
||||
self.connectPorts(self.segment[0].q_sans, self.q_sans)
|
||||
self.connectPorts(self.segment[-1].q_send, self.q_send)
|
||||
self.connectPorts(self.segment[-1].car_out, self.car_out)
|
||||
self.connectPorts(self.segment[0].exits, self.exits)
|
||||
self.connectPorts(self.segment[0].q_sans_bs, self.q_sans_bs)
|
||||
|
||||
for i in range(segments):
|
||||
if i == 0:
|
||||
continue
|
||||
self.connectPorts(self.segment[i].q_sans, self.segment[i-1].q_rans)
|
||||
self.connectPorts(self.segment[i-1].q_send, self.segment[i].q_recv)
|
||||
self.connectPorts(self.segment[i-1].car_out, self.segment[i].car_in)
|
||||
|
||||
class IntersectionState():
|
||||
def __init__(self, switch_signal):
|
||||
self.send_query = []
|
||||
self.send_ack = []
|
||||
self.send_car = []
|
||||
self.queued_queries = []
|
||||
self.id_locations = [None, None, None, None]
|
||||
self.block = vertical
|
||||
self.switch_signal = switch_signal
|
||||
self.ackDir = {}
|
||||
|
||||
def __str__(self):
|
||||
return "ISECT blocking " + str(self.block)
|
||||
return "Intersection: send_query = " + str(self.send_query) + ", send_ack = " + str(self.send_ack) + ", send_car = " + str(self.send_car) + ", block = " + str(self.block)
|
||||
|
||||
def copy(self):
|
||||
new = IntersectionState(self.switch_signal)
|
||||
new.send_query = [q.copy() for q in self.send_query]
|
||||
new.send_ack = [a.copy() for a in self.send_ack]
|
||||
new.send_car = [c.copy() for c in self.send_car]
|
||||
new.queued_queries = [q.copy() for q in self.queued_queries]
|
||||
new.id_locations = list(self.id_locations)
|
||||
new.block = self.block
|
||||
new.switch_signal = self.switch_signal
|
||||
new.ackDir = dict(self.ackDir)
|
||||
return new
|
||||
|
||||
class Intersection(AtomicDEVS):
|
||||
def __init__(self, district, name="Intersection", switch_signal = 30):
|
||||
AtomicDEVS.__init__(self, name=name)
|
||||
self.state = IntersectionState(switch_signal)
|
||||
self.switch_signal_delay = switch_signal
|
||||
self.district = district
|
||||
|
||||
self.q_send = []
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_n"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_e"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_s"))
|
||||
self.q_send.append(self.addOutPort(name="q_send_to_w"))
|
||||
|
||||
self.q_rans = []
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_n"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_e"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_s"))
|
||||
self.q_rans.append(self.addInPort(name="q_rans_from_w"))
|
||||
|
||||
self.q_recv = []
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_n"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_e"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_s"))
|
||||
self.q_recv.append(self.addInPort(name="q_recv_from_w"))
|
||||
|
||||
self.q_sans = []
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_n"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_e"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_s"))
|
||||
self.q_sans.append(self.addOutPort(name="q_sans_to_w"))
|
||||
|
||||
self.car_in = []
|
||||
self.car_in.append(self.addInPort(name="car_in_from_n"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_e"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_s"))
|
||||
self.car_in.append(self.addInPort(name="car_in_from_w"))
|
||||
|
||||
self.car_out = []
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_n"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_e"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_s"))
|
||||
self.car_out.append(self.addOutPort(name="car_out_to_w"))
|
||||
|
||||
def intTransition(self):
|
||||
self.state.switch_signal -= self.timeAdvance()
|
||||
if self.state.switch_signal <= 1e-6:
|
||||
# We switched our traffic lights
|
||||
self.state.switch_signal = self.switch_signal_delay
|
||||
self.state.queued_queries = []
|
||||
self.state.block = vertical if self.state.block == horizontal else horizontal
|
||||
|
||||
for loc, car_id in enumerate(self.state.id_locations):
|
||||
# Notify all cars that got 'green' that they should not continue
|
||||
if car_id is None:
|
||||
continue
|
||||
try:
|
||||
if str(loc) in self.state.block:
|
||||
query = Query(car_id)
|
||||
query.direction = int_to_dir[self.state.ackDir[car_id]]
|
||||
self.state.queued_queries.append(query)
|
||||
except KeyError:
|
||||
pass
|
||||
self.state.send_car = []
|
||||
self.state.send_query = []
|
||||
self.state.send_ack = []
|
||||
return self.state
|
||||
|
||||
def extTransition(self, inputs):
|
||||
# Simple forwarding of all messages
|
||||
# Unless the direction in which it is going is blocked
|
||||
self.state.switch_signal -= self.elapsed
|
||||
for direction in range(4):
|
||||
blocked = str(direction) in self.state.block
|
||||
for car in inputs.get(self.car_in[direction], []):
|
||||
self.state.send_car.append(car)
|
||||
# Got a car, so remove its ID location entry
|
||||
try:
|
||||
del self.state.ackDir[car.ID]
|
||||
self.state.id_locations[self.state.id_locations.index(car.ID)] = None
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
self.state.queued_queries = [query for query in self.state.queued_queries if query.ID != car.ID]
|
||||
for query in inputs.get(self.q_recv[direction], []):
|
||||
self.state.id_locations[direction] = query.ID
|
||||
self.state.ackDir[query.ID] = dir_to_int[query.direction]
|
||||
if blocked:
|
||||
self.state.send_ack.append(QueryAck(query.ID, INFINITY))
|
||||
self.state.queued_queries.append(query)
|
||||
else:
|
||||
self.state.send_query.append(query)
|
||||
for ack in inputs.get(self.q_rans[direction], []):
|
||||
self.state.ackDir[ack.ID] = direction
|
||||
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)):
|
||||
try:
|
||||
self.state.id_locations.index(ack.ID)
|
||||
t_until_dep = INFINITY
|
||||
nquery = Query(ack.ID)
|
||||
nquery.direction = int_to_dir[direction]
|
||||
self.state.queued_queries.append(nquery)
|
||||
except ValueError:
|
||||
continue
|
||||
else:
|
||||
t_until_dep = ack.t_until_dep
|
||||
self.state.send_ack.append(QueryAck(ack.ID, t_until_dep))
|
||||
return self.state
|
||||
|
||||
def outputFnc(self):
|
||||
# Can simply overwrite, as multiple calls to the same destination is impossible
|
||||
toSend = {}
|
||||
new_block = vertical if self.state.block == horizontal else horizontal
|
||||
if self.state.switch_signal == self.timeAdvance():
|
||||
# We switch our traffic lights
|
||||
# Resend all queries for those that are waiting
|
||||
for query in self.state.queued_queries:
|
||||
if str(self.state.id_locations.index(query.ID)) not in new_block:
|
||||
toSend[self.q_send[dir_to_int[query.direction]]] = [query]
|
||||
for loc, car_id in enumerate(self.state.id_locations):
|
||||
# Notify all cars that got 'green' that they should not continue
|
||||
if car_id is None:
|
||||
continue
|
||||
if str(loc) in new_block:
|
||||
toSend[self.q_sans[loc]] = [QueryAck(car_id, INFINITY)]
|
||||
else:
|
||||
try:
|
||||
query = Query(car_id)
|
||||
query.direction = int_to_dir[self.state.ackDir[car_id]]
|
||||
toSend[self.q_send[self.state.ackDir[car_id]]] = [query]
|
||||
except KeyError:
|
||||
pass
|
||||
# We might have some messages to forward too
|
||||
for car in self.state.send_car:
|
||||
dest = car.path.pop(0)
|
||||
toSend[self.car_out[dir_to_int[dest]]] = [car]
|
||||
for query in self.state.send_query:
|
||||
toSend[self.q_send[dir_to_int[query.direction]]] = [query]
|
||||
for ack in self.state.send_ack:
|
||||
# Broadcast for now
|
||||
try:
|
||||
toSend[self.q_sans[self.state.id_locations.index(ack.ID)]] = [ack]
|
||||
except ValueError:
|
||||
pass
|
||||
return toSend
|
||||
|
||||
def timeAdvance(self):
|
||||
if len(self.state.send_car) + len(self.state.send_query) + len(self.state.send_ack) > 0:
|
||||
return 0.0
|
||||
else:
|
||||
return max(self.state.switch_signal, 0.0)
|
||||
|
||||
class CollectorState(object):
|
||||
def __init__(self):
|
||||
self.cars = []
|
||||
|
||||
def copy(self):
|
||||
new = CollectorState()
|
||||
new.cars = list(self.cars)
|
||||
return new
|
||||
|
||||
def __str__(self):
|
||||
## Print your statistics here!
|
||||
s = "All cars collected:"
|
||||
for car in self.cars:
|
||||
s += "\n\t\t\t%s" % car
|
||||
return s
|
||||
|
||||
class Collector(AtomicDEVS):
|
||||
def __init__(self):
|
||||
AtomicDEVS.__init__(self, "Collector")
|
||||
self.car_in = self.addInPort("car_in")
|
||||
self.state = CollectorState()
|
||||
self.district = 0
|
||||
|
||||
def extTransition(self, inputs):
|
||||
self.state.cars.extend(inputs[self.car_in])
|
||||
return self.state
|
||||
17
models/dist_activity_citylayout/plot
Normal file
17
models/dist_activity_citylayout/plot
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
reset
|
||||
set key top left
|
||||
set terminal postscript enhanced color portrait size 10,6
|
||||
|
||||
set pointsize 1.5
|
||||
|
||||
set out 'dist_activity_citylayout_cluster.eps'
|
||||
set title 'Citylayout model for different relocators (5 nodes)'
|
||||
set xlabel 'Microseconds artificial load'
|
||||
set ylabel 'Time (s)'
|
||||
plot 'dist_activity_citylayout/cluster_5/results_NO' using (($1)/54):(($2+$3+$4)/3) with linespoint lw 5 title 'No relocation', 'dist_activity_citylayout/cluster_5/results_AT' using (($1)/54):(($2+$3+$4)/3) lw 5 title 'Activity tracking' with linespoint, 'dist_activity_citylayout/cluster_5/results_CA' using (($1)/54):(($2+$3+$4)/3) lw 5 title 'Custom activity tracking' with linespoint, 'dist_activity_citylayout/cluster_5/results_CACR' using (($1)/54):(($2+$3+$4)/3) lw 5 title 'Custom activity Prediction' with linespoint
|
||||
|
||||
set out 'dist_activity_citylayout.eps'
|
||||
set title 'Citylayout model for different relocators (3 nodes)'
|
||||
set xlabel 'Microseconds artificial load'
|
||||
set ylabel 'Time (s)'
|
||||
plot 'dist_activity_citylayout/local_3/results_NO' using (($1)/54):($2) title 'No relocation' w l, 'dist_activity_citylayout/local_3/results_AT' using (($1)/54):($2) title 'Activity tracking' w l, 'dist_activity_citylayout/local_3/results_CA' using (($1)/54):($2) title 'Custom activity tracking' w l, 'dist_activity_citylayout/local_3/results_CACR' using (($1)/54):($2) title 'Custom activity Prediction' w l
|
||||
8
models/dist_activity_citylayout/results_AT
Normal file
8
models/dist_activity_citylayout/results_AT
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 73.0682880878
|
||||
10000 83.1141879559
|
||||
15000 95.2681729794
|
||||
20000 118.08734107
|
||||
25000 153.53333497
|
||||
30000 187.269927025
|
||||
35000 240.79185605
|
||||
40000 273.546699047
|
||||
8
models/dist_activity_citylayout/results_CA
Normal file
8
models/dist_activity_citylayout/results_CA
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 74.27176404
|
||||
10000 85.0585899353
|
||||
15000 102.62780714
|
||||
20000 119.98334384
|
||||
25000 145.06695509
|
||||
30000 178.447484016
|
||||
35000 210.980580091
|
||||
40000 250.771591902
|
||||
8
models/dist_activity_citylayout/results_CACR
Normal file
8
models/dist_activity_citylayout/results_CACR
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 76.6213350296
|
||||
10000 85.123511076
|
||||
15000 97.6058199406
|
||||
20000 118.191107035
|
||||
25000 141.368769884
|
||||
30000 173.305505037
|
||||
35000 213.74692893
|
||||
40000 250.871848106
|
||||
8
models/dist_activity_citylayout/results_NO
Normal file
8
models/dist_activity_citylayout/results_NO
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
5000 77.1485600471
|
||||
10000 91.3756399155
|
||||
15000 106.805973053
|
||||
20000 128.162094116
|
||||
25000 155.74973321
|
||||
30000 187.734708071
|
||||
35000 223.016438007
|
||||
40000 266.565794945
|
||||
26
models/dist_activity_citylayout/test_city_AT.py
Normal file
26
models/dist_activity_citylayout/test_city_AT.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import sys
|
||||
sys.path.append("../../src/")
|
||||
sys.path.append("dist_activity_citylayout/activity_tracking/")
|
||||
from trafficModels import *
|
||||
from generated_city import City
|
||||
from simulator import Simulator
|
||||
import time
|
||||
if __name__ == '__main__':
|
||||
city = City()
|
||||
from mpi4py import MPI
|
||||
if MPI.COMM_WORLD.Get_size() == 1:
|
||||
city.setLocation(0, force=True)
|
||||
sim = Simulator(city)
|
||||
#sim.setVerbose(None)
|
||||
sim.setStateSaving('custom')
|
||||
#sim.setMemoization()
|
||||
sim.setMessageCopy('custom')
|
||||
sim.setTerminationTime(5000.0)
|
||||
sim.setSchedulerHeapSet()
|
||||
sim.setGVTInterval(2)
|
||||
sim.setActivityRelocatorCustom('relocator', 'CityRelocator')
|
||||
start = time.time()
|
||||
sim.simulate()
|
||||
print('Arrived: ' + str(len(city.collector.state.cars)/468.0))
|
||||
print("Simulation time: " + str(time.time() - start))
|
||||
|
||||
25
models/dist_activity_citylayout/test_city_CA.py
Normal file
25
models/dist_activity_citylayout/test_city_CA.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import sys
|
||||
sys.path.append("../../src/")
|
||||
sys.path.append("dist_activity_citylayout/custom_activity/")
|
||||
from trafficModels import *
|
||||
from generated_city import City
|
||||
from simulator import Simulator
|
||||
import time
|
||||
if __name__ == '__main__':
|
||||
city = City()
|
||||
from mpi4py import MPI
|
||||
if MPI.COMM_WORLD.Get_size() == 1:
|
||||
city.setLocation(0, force=True)
|
||||
sim = Simulator(city)
|
||||
#sim.setVerbose(None)
|
||||
sim.setStateSaving('custom')
|
||||
sim.setMemoization()
|
||||
sim.setMessageCopy('custom')
|
||||
sim.setTerminationTime(5000.0)
|
||||
sim.setGVTInterval(5)
|
||||
sim.setActivityRelocatorCustom('relocator_custom_activity', 'CityRelocator')
|
||||
start = time.time()
|
||||
sim.simulate()
|
||||
print('Arrived: ' + str(len(city.collector.state.cars)/468.0))
|
||||
print("Simulation time: " + str(time.time() - start))
|
||||
|
||||
25
models/dist_activity_citylayout/test_city_CACR.py
Normal file
25
models/dist_activity_citylayout/test_city_CACR.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import sys
|
||||
sys.path.append("../../src/")
|
||||
sys.path.append("dist_activity_citylayout/custom_activity_custom_relocator/")
|
||||
from trafficModels import *
|
||||
from generated_city import City
|
||||
from simulator import Simulator
|
||||
import time
|
||||
if __name__ == '__main__':
|
||||
city = City()
|
||||
from mpi4py import MPI
|
||||
if MPI.COMM_WORLD.Get_size() == 1:
|
||||
city.setLocation(0, force=True)
|
||||
sim = Simulator(city)
|
||||
#sim.setVerbose(None)
|
||||
sim.setStateSaving('custom')
|
||||
sim.setMemoization()
|
||||
sim.setMessageCopy('custom')
|
||||
sim.setTerminationTime(5000.0)
|
||||
sim.setGVTInterval(5)
|
||||
sim.setActivityRelocatorCustom('relocator_custom_activity', 'CityRelocator')
|
||||
start = time.time()
|
||||
sim.simulate()
|
||||
print('Arrived: ' + str(len(city.collector.state.cars)/468.0))
|
||||
print("Simulation time: " + str(time.time() - start))
|
||||
|
||||
24
models/dist_activity_citylayout/test_city_NO.py
Normal file
24
models/dist_activity_citylayout/test_city_NO.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import sys
|
||||
sys.path.append("../../src/")
|
||||
sys.path.append("dist_activity_citylayout/no_activity_tracking/")
|
||||
from trafficModels import *
|
||||
from generated_city import City
|
||||
from simulator import Simulator
|
||||
import time
|
||||
if __name__ == '__main__':
|
||||
city = City()
|
||||
from mpi4py import MPI
|
||||
if MPI.COMM_WORLD.Get_size() == 1:
|
||||
city.setLocation(0, force=True)
|
||||
sim = Simulator(city)
|
||||
#sim.setVerbose(None)
|
||||
sim.setStateSaving('custom')
|
||||
sim.setMemoization()
|
||||
sim.setMessageCopy('custom')
|
||||
sim.setTerminationTime(5000.0)
|
||||
sim.setGVTInterval(5)
|
||||
start = time.time()
|
||||
sim.simulate()
|
||||
print('Arrived: ' + str(len(city.collector.state.cars)/468.0))
|
||||
print("Simulation time: " + str(time.time() - start))
|
||||
|
||||
28
models/dist_activity_citylayout/timer.py
Normal file
28
models/dist_activity_citylayout/timer.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#!/bin/env python
|
||||
import sys
|
||||
sys.path.append("../../src/")
|
||||
|
||||
import time
|
||||
|
||||
sys.setrecursionlimit(10000)
|
||||
|
||||
tests = ["AT", "CACR", "NO", "CA"]
|
||||
loads = range(5000, 45000, 5000)
|
||||
|
||||
iters = int(sys.argv[1])
|
||||
|
||||
for relocator in tests:
|
||||
f = open("dist_activity_citylayout/results_%s" % relocator, 'w')
|
||||
for load in loads:
|
||||
total = 0.0
|
||||
for _ in range(iters):
|
||||
command = "mpirun -np 3 python dist_activity_citylayout/test_city_%s.py %s" % (relocator, load)
|
||||
output = open("/tmp/output", 'w')
|
||||
import subprocess
|
||||
start = time.time()
|
||||
subprocess.call(command, shell=True, stdout=output)
|
||||
output.close()
|
||||
total += (time.time() - start)
|
||||
f.write("%s %s\n" % (load, total/iters))
|
||||
print("%s %s" % (load, total/iters))
|
||||
f.close()
|
||||
Loading…
Add table
Add a link
Reference in a new issue