Question: Python (Discrete Event Systems and PyLab) question Consider the simulation below for a drive-through with two stations, one for ordering and one for picking up.
Python (Discrete Event Systems and PyLab) question
Consider the simulation below for a drive-through with two stations, one for ordering and one for picking up. All customers first line up for ordering and then line up for picking up. We assume, for simplicity, that all queues are unbounded, also the queue for picking up (although in most drive-throughs that would be limited to 3 cars). The program is similar to the discrete event system from class, except that more global variables are used to avoid passing them around as parameters: LAMBD, MU1, MU2 are the parameters of the exponential distribution for the inter-arrival time of new customers, for the time for paying, and for the time for picking up (recall that if is the parameter of the exponential distribution, the average time is 1/). Also, SIM, ORDER, PICKUP are global variables for the simulation (the sole object of class `Simulation`), order station, and pickup station (objects of class `Station`).
import random import matplotlib.pylab as pylab
pylab.ion()
class Path: def __init__(self): self.w, self.n, self.t, self.ns = 0, 0, 0, [] def up(self, t): self.w = self.w + self.n * (t - self.t) self.n, self.t = self.n + 1, t self.ns.append(self.n) def down(self, t): self.w = self.w + self.n * (t - self.t) self.n, self.t = self.n - 1, t self.ns.append(self.n) def mean(self, t_end): return (self.w + self.n * (t_end - self.t)) / t_end def hist(self): pylab.xlabel('Length of queue') pylab.ylabel('Frequency') pylab.hist(self.ns, bins = range(max(self.ns) + 3), normed = True)
class Event: def __init__(self, time, actor, msg): self.time, self.actor, self.msg = time, actor, msg def __lt__(self, other): return self.time < other.time
class Simulator: def __init__(self): self.calendar, self.time = set(), 0.0 def schedule(self, time, actor, msg): if LOG: print(actor, msg, 'scheduled at', self.time + time) self.calendar.add(Event(self.time + time, actor, msg)) def simulate(self, dt): t_end = self.time + dt while self.time <= t_end: cur = min(self.calendar) self.calendar.remove(cur) self.time = cur.time if LOG: print('advancing time to', self.time) cur.actor.handle(cur.msg) return len(self.calendar) # return number of unprocessed events
class Station: def __init__(self, name): self.wl = [] # FIFO waiting line: len(), pop(0), append(x) self.path = Path() self.name = name def __str__(self): return self.name def request(self, customer): if self.path.n == 0: # server empty if LOG: print('station', self.name, 'serving immediately', str(customer)) customer.handle('serve') else: if LOG: print('station', self.name, 'enqueuing', str(customer)) self.wl.append(customer) self.path.up(SIM.time) def free(self): self.path.down(SIM.time) if len(self.wl) > 0: # customers are waiting if LOG: print('station', self.name, 'serving next in line') customer = self.wl.pop(0) # first waiting customer customer.handle('serve')
class Source: def __init__(self, name, station): self.name, self.station = name, station self.c = 1 # count for created customers def __str__(self): return self.name def handle(self, msg): self.station.request(Customer(self.name + ' Customer ' + str(self.c), self.station)) SIM.schedule(random.expovariate(LAMBD), self, '') self.c = self.c + 1
class Customer: ts = [] # total times for drive-through, shared among all customers def __init__(self, name, station): self.name, self.station, self.t_start = name, station, SIM.time def __str__(self): return self.name def handle(self, msg): if self.station == ORDER: if msg == 'serve': if LOG: print('customer', self.name, 'is ordering') SIM.schedule(random.expovariate(MU1), self, 'leave') else: # msg == 'leave' if LOG: print('customer', self.name, 'has ordered') ORDER.free(); self.station = PICKUP; PICKUP.request(self) else: # self.station == PICKUP: if msg == 'serve': if LOG: print('customer', self.name, 'is picking up') SIM.schedule(random.expovariate(MU2), self, 'leave') else: # msg == 'leave' if LOG: print('customer', self.name, 'has picked up') PICKUP.free() Customer.ts.append(SIM.time - self.t_start) def hist(): pylab.figure() pylab.xlabel('Total Drive-Through Time') pylab.ylabel('Frequency') pylab.hist(Customer.ts, bins = range(15), normed = True)
def simulateTwoStationDriveThrough(dt, t_arrival, t_order, t_pickup): """ dt: pediod of simulation t_arrival: average customer inter-arrival time with exponential distribution t_order: average time order time with exponential distribution t_pickup: average of food preparation time returns average total waiting time at both stations """ global LAMBD, MU1, MU2 LAMBD, MU1, MU2 = 1 / t_arrival, 1 / t_order, 1 / t_pickup global SIM, ORDER, PICKUP SIM = Simulator() ORDER = Station('Order') PICKUP = Station('Pickup') sr = Source('SR', ORDER) SIM.schedule(0, sr, '') SIM.simulate(dt) return ORDER.path.mean(dt) + PICKUP.path.mean(dt)
LOG = False
-----------------------------------------------------------------------------
The task is to analyze what happens if ordering is split up into ordering and paying, that is, the drive-through has three stations. Define a function `simulateThreeStationDriveThrough(dt, t_arrival, t_order, t_pay, t_pickup)` that is similar to `simulateTwoStationDriveThrough(dt, t_arrival, t_order, t_pickup)`, but with one extra parameter, `t_pay`, for the average time for payment; `t_order` is now the time for ordering without payment. For this, you will need to modify class `Customer` to reflect the new behavior of customers, who now first order, then pay, then pick up.
class Customer: ts = [] # total times for drive-through, shared among all customers def __init__(self, name, station): self.name, self.station, self.t_start = name, station, SIM.time def __str__(self): return self.name def handle(self, msg): # replace with your body def hist(): pylab.figure() pylab.xlabel('Total Drive-Through Time') pylab.ylabel('Frequency') pylab.hist(Customer.ts, bins = range(15), normed = True)
def simulateThreeStationDriveThrough(dt, t_arrival, t_order, t_pay, t_pickup): """ dt: pediod of simulation t_arrival: average customer inter-arrival time with exponential distribution t_order: average time order time with exponential distribution t_pay: average time for payment with exponential distribution t_pickup: average of food preparation time returns average total waiting time at all three stations """ # replace with your body
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
