Skip to content

Instantly share code, notes, and snippets.

@Zamony
Last active September 4, 2018 19:02
Show Gist options
  • Save Zamony/c1c7c29729521f3a24c4717fd5d34b80 to your computer and use it in GitHub Desktop.
Save Zamony/c1c7c29729521f3a24c4717fd5d34b80 to your computer and use it in GitHub Desktop.
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