Last active
September 4, 2018 19:02
-
-
Save Zamony/c1c7c29729521f3a24c4717fd5d34b80 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math | |
import random | |
import simpy | |
SECS_PER_HOUR = 60*60 | |
# Exponental distribution | |
# People/Seconds | |
Q1SPEED = 14 / SECS_PER_HOUR | |
Q2SPEED = 10 / SECS_PER_HOUR | |
Q3SPEED = 24 / SECS_PER_HOUR | |
# Miles/seconds | |
BUS_SPEED = 30/SECS_PER_HOUR | |
# No m. units | |
BUS_CAPACITY = 20 | |
BUS_START_POINT = 3 | |
# Time in seconds | |
T31 = int( 4.5 / BUS_SPEED ) | |
T12 = int( 1.0 / BUS_SPEED ) | |
T23 = T31 | |
# Probability | |
PROBQ1 = 0.583 | |
PROBQ2 = 0.417 | |
# Uniform distribution | |
# In seconds | |
LBLEAVE = 16 | |
RBLEAVE = 24 | |
LBIN = 15 | |
RBIN = 25 | |
# In seconds | |
MIN_TIME_AT_STOP = 5*60 | |
# In seconds | |
MODEL_UNTIL = 2*SECS_PER_HOUR | |
class BusSim: | |
def __init__(self, env): | |
self.env = env | |
self.q1 = [] | |
self.q2 = [] | |
self.q3 = [] | |
self.passengers = [] | |
# Statistical information | |
# Total number of people seen in the queue | |
self.sum_pq1 = 0 | |
self.sum_pq2 = 0 | |
self.sum_pq3 = 0 | |
self.max_q1 = 0 | |
self.max_q2 = 0 | |
self.max_q3 = 0 | |
# The number of observations | |
self.obs_q1 = 0 | |
self.obs_q2 = 0 | |
self.obs_q3 = 0 | |
# Passengers | |
self.psum = 0 | |
self.pmax = 0 | |
# Time, wasted | |
self.sum_tq1 = 0 | |
self.sum_tq2 = 0 | |
self.sum_tq3 = 0 | |
self.min_tq1 = math.inf | |
self.min_tq2 = math.inf | |
self.min_tq3 = math.inf | |
self.max_tq1 = 0 | |
self.max_tq2 = 0 | |
self.max_tq3 = 0 | |
# Loop time | |
self.max_lt = 0 | |
self.min_lt = math.inf | |
self.sum_lt = 0 | |
self.loops_count = -1 | |
self.prev_time = None | |
# People waited | |
self.sum_pw = 0 | |
self.max_pw = 0 | |
self.people_cnt = 0 | |
self.min_pw = math.inf | |
def startDriving(self): | |
arrived_at = self.env.now | |
# Refactoring needed, queues = [ [], [], [] ] | |
curr_qid = BUS_START_POINT | |
curr_q = self.q3 | |
print("Автобус в точке {}".format(curr_qid)) | |
self._updateQueueStats(curr_qid) | |
while True: | |
not_in_hurry = (self.env.now - arrived_at) <= MIN_TIME_AT_STOP | |
can_take_psgrs = ( | |
len(curr_q) > 0 and | |
len(self.passengers) < BUS_CAPACITY | |
) | |
while not_in_hurry or can_take_psgrs: | |
if can_take_psgrs: | |
psgr = curr_q.pop(0) | |
ttw = random.randint( LBIN, RBIN ) | |
yield self.env.timeout( ttw ) | |
print("Сажаю пасс. {}".format( psgr.id )) | |
self._updatePeopleWaited(psgr.arrival_time) | |
self.passengers.append( psgr ) | |
else: | |
yield self.env.timeout(1) | |
not_in_hurry = (self.env.now - arrived_at) <= MIN_TIME_AT_STOP | |
can_take_psgrs = ( | |
len(curr_q) > 0 and | |
len(self.passengers) != BUS_CAPACITY | |
) | |
# The bus started driving | |
self._updateTimeWastedStats(curr_qid, self.env.now - arrived_at) | |
self._updatePsgrsInBusStats() | |
self._updateLoopTime(curr_qid, self.env.now) | |
if curr_qid == 3: | |
curr_q = self.q1 | |
curr_qid = 1 | |
yield self.env.timeout(T31) | |
elif curr_qid == 1: | |
curr_q = self.q2 | |
curr_qid = 2 | |
yield self.env.timeout(T12) | |
else: | |
curr_q = self.q3 | |
curr_qid = 3 | |
yield self.env.timeout(T23) | |
print("Автобус в точке {}".format(curr_qid)) | |
self._updateQueueStats(curr_qid) | |
remained_psgrs = [] | |
arrived_at = self.env.now | |
for psgr in self.passengers: | |
if psgr.dest != curr_qid: | |
remained_psgrs.append(psgr) | |
else: | |
ttw = random.randint( LBLEAVE, RBLEAVE ) | |
yield self.env.timeout( ttw ) | |
print("Высаживаю пасс. {}".format( psgr.id )) | |
self.passengers = remained_psgrs | |
def startArrival(self, qid, speed): | |
while True: | |
time_to_wait = int( random.expovariate( speed ) ) | |
yield self.env.timeout( time_to_wait ) | |
if qid == 1: | |
self.q1.append( Passenger( qid, self.env.now, 3 ) ) | |
elif qid == 2: | |
self.q2.append( Passenger( qid, self.env.now, 3 ) ) | |
else: | |
self.q3.append( Passenger( qid, self.env.now, None ) ) | |
def _updateQueueStats(self, qid): | |
if qid == 1: | |
ql = len( self.q1 ) | |
self.sum_pq1 += ql | |
self.max_q1 = max( ql, self.max_q1 ) | |
self.obs_q1 += 1 | |
elif qid == 2: | |
ql = len( self.q2 ) | |
self.sum_pq2 += ql | |
self.max_q2 = max( ql, self.max_q2 ) | |
self.obs_q2 += 1 | |
else: | |
ql = len( self.q3 ) | |
self.sum_pq3 += ql | |
self.max_q3 = max( ql, self.max_q3 ) | |
self.obs_q3 += 1 | |
def _updateTimeWastedStats(self, qid, time): | |
if qid == 1: | |
self.sum_tq1 += time | |
self.min_tq1 = min( self.min_tq1, time ) | |
self.max_tq1 = max( self.max_tq1, time ) | |
elif qid == 2: | |
self.sum_tq2 += time | |
self.min_tq2 = min( self.min_tq2, time ) | |
self.max_tq2 = max( self.max_tq2, time ) | |
else: | |
self.sum_tq3 += time | |
self.min_tq3 = min( self.min_tq3, time ) | |
self.max_tq3 = max( self.max_tq3, time ) | |
def _updatePsgrsInBusStats(self): | |
self.psum += len( self.passengers ) | |
self.pmax = max( len( self.passengers ), self.pmax ) | |
def _updateLoopTime(self, qid, time): | |
if qid == 3: | |
if self.prev_time is not None: | |
lt = time - self.prev_time | |
self.max_lt = max(lt, self.max_lt) | |
self.min_lt = min(lt, self.min_lt) | |
self.sum_lt += lt | |
self.prev_time = time | |
self.loops_count += 1 | |
def _updatePeopleWaited(self, arr_time): | |
time = self.env.now - arr_time | |
self.sum_pw += time | |
self.max_pw = max( self.max_pw, time ) | |
self.min_pw = min( self.min_pw, time ) | |
self.people_cnt += 1 | |
def displayStats(self): | |
# Original time measures in seconds | |
print("Все время ниже - в минутах") | |
print("Средняя очередь в 1, 2, 3 соотв.") | |
print("{0:.2f}".format(self.sum_pq1 / self.obs_q1), end=" ") | |
print("{0:.2f}".format(self.sum_pq2 / self.obs_q2), end=" ") | |
print("{0:.2f}".format(self.sum_pq3 / self.obs_q3) ) | |
print("Макс. очередь в 1, 2, 3 соотв.") | |
print(self.max_q1, end=" ") | |
print(self.max_q2, end=" ") | |
print(self.max_q3) | |
print("Среднее и макс. число пассажиров в автобусе") | |
print( | |
"{0:.2f}".format( | |
self.psum / ( self.obs_q1 + self.obs_q2 + self.obs_q3 ) | |
), end=" " | |
) | |
print(self.pmax) | |
print("Среднее время в пунктах 1, 2, 3 соотв.") | |
print("{0:.2f}".format(self.sum_tq1 / self.obs_q1 / 60), end=" ") | |
print("{0:.2f}".format(self.sum_tq2 / self.obs_q2 / 60), end=" ") | |
print("{0:.2f}".format(self.sum_tq3 / self.obs_q3 / 60) ) | |
print("Мин. время в пунктах 1, 2, 3 соотв.") | |
print(self.min_tq1 / 60, end=" ") | |
print(self.min_tq2 / 60, end=" ") | |
print(self.min_tq3 / 60) | |
print("Макс. время в пунктах 1, 2, 3 соотв.") | |
print("{0:.2f}".format(self.max_tq1 / 60), end=" ") | |
print("{0:.2f}".format(self.max_tq2 / 60), end=" ") | |
print("{0:.2f}".format(self.max_tq3 / 60)) | |
print("Макс., мин., среднее время круга соотв.") | |
print("{0:.2f}".format(self.max_lt / 60), end=" ") | |
print("{0:.2f}".format(self.min_lt / 60), end=" ") | |
print("{0:.2f}".format(self.sum_lt / self.loops_count / 60)) | |
print("Среднее, макс., мин., время ожидания у пассажира.") | |
print("{0:.2f}".format(self.sum_pw / self.people_cnt / 60), end=" ") | |
print("{0:.2f}".format(self.max_pw / 60, end=" ")) | |
print("{0:.2f}".format(self.min_pw / 60)) | |
class Passenger: | |
counter = 0 | |
def __init__(self, qid, time, dest=None): | |
self.qid = qid | |
self.arrival_time = time | |
self.dest = self._askDestination(dest) | |
self.id = Passenger.counter | |
#print("В очереди {} пасс. {}".format( qid, self.id )) | |
Passenger.counter += 1 | |
def _askDestination(self, dest): | |
if dest is not None: | |
return dest | |
if random.random() < PROBQ1: | |
return 1 | |
return 2 | |
if __name__ == "__main__": | |
env = simpy.Environment() | |
bm = BusSim(env) | |
env.process( bm.startDriving() ) | |
env.process( bm.startArrival(1, Q1SPEED) ) | |
env.process( bm.startArrival(2, Q2SPEED) ) | |
env.process( bm.startArrival(3, Q3SPEED) ) | |
env.run( until=MODEL_UNTIL ) | |
bm.displayStats() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment