Python - Simpy 4.0.1 - 环境中的多种输入
Python - Simpy 4.0.1 - multiple kinds of inputs in an Environment
我一直在解决一个问题,我必须在 Simpy 4.0.1 程序中模拟治疗中心的患者,该程序有多个类别的患者(比如“A”、“B”和“C”) .患者根据 numpy.random.exponential()
产生的超时“到达”,并根据 numpy.random.lognormal()
在中心“占床”(Simpy 资源)。每种患者类型都有一组不同的值来控制此采样。这是一个简单的 FIFO 过程,不涉及优先级,患者只是以不同的速度到达和停留。
我尝试的第一种方法是为每一类患者创建 3 个进程,并让 Simpy 处理它们的生成:
import simpy
from numpy.random import exponential, lognormal
counter = 0
total_beds = 5
run_length = 10
mean_iat_a, mean_iat_b, mean_iat_c = 1.0, 2.0, 3.0
normal_mean_a, normal_mean_b, normal_mean_c = 4.0, 5.0, 6.0
normal_stdev_a, normal_stdev_b, normal_stdev_c = 7.0, 8.0, 9.0
class Patient:
def __init__(self, pid, ptype):
self.pid = pid
self.ptype = ptype
self.time_arrived = None
self.time_admitted = None
self.time_discharged = None
def generate_arrivals(env, ptype):
while True:
global counter
counter += 1
patient = Patient(counter, ptype)
env.process(perform_treatment(env, patient))
# sample arrivals
if patient.ptype == 'A':
interarival_time = exponential(scale=mean_iat_a)
elif patient.ptype == 'B':
interarival_time = exponential(scale=mean_iat_b)
else:
interarival_time = exponential(scale=mean_iat_c)
yield env.timeout(interarival_time)
def perform_treatment(env, patient):
patient.time_arrived = env.now
print(f'Patient {patient.pid} - {patient.ptype} - arrived at {patient.time_arrived}')
with beds.request() as req:
yield req
patient.time_admitted = env.now
print(f'Patient {patient.pid} - {patient.ptype} - admitted at {patient.time_admitted}')
# sample duration of stay
if patient.ptype == 'A':
stay_duration = lognormal(mean=normal_mean_a, sigma=normal_stdev_a)
elif patient.ptype == 'B':
stay_duration = lognormal(mean=normal_mean_b, sigma=normal_stdev_b)
else:
stay_duration = lognormal(mean=normal_mean_c, sigma=normal_stdev_c)
yield env.timeout(stay_duration)
patient.time_discharged = env.now
print(f'Patient {patient.pid} - {patient.ptype} - discharged at {patient.time_discharged}')
env = simpy.Environment()
beds = simpy.Resource(env, capacity=total_beds)
env.process(generate_arrivals(env, 'A'))
env.process(generate_arrivals(env, 'B'))
env.process(generate_arrivals(env, 'C'))
env.run(until=run_length)
这种方法的问题在于,每个类别的患者在其各自流程开始时都会创建(它总是在时间 = 0 时创建每个类别的患者 1、2 和 3),但它不会反映真实场景:
Patient 1 - A - arrived at 0
Patient 2 - B - arrived at 0
Patient 3 - C - arrived at 0
Patient 1 - A - admitted at 0
Patient 2 - B - admitted at 0
Patient 3 - C - admitted at 0
Patient 1 - A - discharged at 0.04165029350880402
Patient 4 - A - arrived at 0.6503311494436321
Patient 4 - A - admitted at 0.6503311494436321
Patient 4 - A - discharged at 0.6626671650563922
Patient 5 - B - arrived at 0.6868621026906724
.
.
etc
到目前为止,我一直在考虑使用:
- child 类 存储类别特定常量和
- 通过
numpy.random.multinomial()
以相同的概率随机决定生成哪种患者的单个过程。
import simpy
from numpy.random import exponential, lognormal, multinomial
counter = 0
total_beds = 5
run_length = 10
ptypes = ['A', 'B', 'C']
probvals = [1.0 / len(ptypes) for _ in ptypes]
class Patient:
def __init__(self, pid, ptype):
self.pid = pid
self.ptype = ptype
self.time_arrived = None
self.time_admitted = None
self.time_discharged = None
class TypeA(Patient):
def __init__(self, pid, ptype):
super().__init__(pid, ptype)
self.mean_iat = 1.0
self.normal_mean = 4.0
self.normal_stdev = 7.0
class TypeB(Patient):
def __init__(self, pid, ptype):
super().__init__(pid, ptype)
self.mean_iat = 2.0
self.normal_mean = 5.0
self.normal_stdev = 8.0
class TypeC(Patient):
def __init__(self, pid, ptype):
super().__init__(pid, ptype)
self.mean_iat = 3.0
self.normal_mean = 6.0
self.normal_stdev = 9.0
def generate_arrivals(env):
while True:
global counter
counter += 1
ptype = ptypes[multinomial(n=1, pvals=probvals).argmax()]
# From here is where I'm stuck
# Can't understand how to drive the correct object instantiation
# to replace the if-elif-else from the previous example
patient = Patient(counter, ptype)
# Not sure of the logic from here on out
env.process(perform_treatment(env, patient))
interarival_time = exponential(scale=patient.mean_iat)
yield env.timeout(interarival_time)
def perform_treatment(env, patient):
patient.time_arrived = env.now
print(f'Patient {patient.pid} - {patient.ptype} - arrived at {patient.time_arrived}')
with beds.request() as req:
yield req
patient.time_admitted = env.now
print(f'Patient {patient.pid} - {patient.ptype} - admitted at {patient.time_admitted}')
# Again, how do I replace the if-elif-else from the previous example
stay_duration = lognormal(mean=patient.normal_mean, sigma=patient.normal_stdev)
yield env.timeout(stay_duration)
patient.time_discharged = env.now
print(f'Patient {patient.pid} - {patient.ptype} - discharged at {patient.time_discharged}')
env = simpy.Environment()
beds = simpy.Resource(env, capacity=total_beds)
env.process(generate_arrivals(env))
env.run(until=run_length)
但是,我似乎无法理解如何使用 Simpy 来完成它。对我的方法或替代想法的任何意见将不胜感激!
注意: 我知道使用 numpy.random.multinomial()
会导致一次只生成一种患者,但这可能完全是一个不同的问题。
在你的第一个代码中,你能否移动你的 gen patient 代码,你能否将你的超时移到循环的顶部。当然这意味着你不会在时间 0
得到任何病人
您在 env.run 之前启动的每个进程都在时间 0 开始,并且在第一个 yield 之前发生的所有事情都在时间 0 发生。调用 env.timeout 不会影响其他进程。我想到了每个进程和它自己的线程。所以当你的程序调用env.run时。它抓住你的一个进程并创建一个病人,然后在 yield env 等待。 timeout(),然后它会抓取第二个进程,仍然在时间 0,并创建一个患者并在 yield 处暂停。等...等...在短时间内不会在过程中移动,直到它达到产量。这有帮助吗? –
迈克尔
11 小时前 删除
当流程中的第一行是 yield env.timeout() 时,在超时完成并且时间已更新之前什么都不会发生。它具有在进程应该启动时进行调度的效果
我一直在解决一个问题,我必须在 Simpy 4.0.1 程序中模拟治疗中心的患者,该程序有多个类别的患者(比如“A”、“B”和“C”) .患者根据 numpy.random.exponential()
产生的超时“到达”,并根据 numpy.random.lognormal()
在中心“占床”(Simpy 资源)。每种患者类型都有一组不同的值来控制此采样。这是一个简单的 FIFO 过程,不涉及优先级,患者只是以不同的速度到达和停留。
我尝试的第一种方法是为每一类患者创建 3 个进程,并让 Simpy 处理它们的生成:
import simpy
from numpy.random import exponential, lognormal
counter = 0
total_beds = 5
run_length = 10
mean_iat_a, mean_iat_b, mean_iat_c = 1.0, 2.0, 3.0
normal_mean_a, normal_mean_b, normal_mean_c = 4.0, 5.0, 6.0
normal_stdev_a, normal_stdev_b, normal_stdev_c = 7.0, 8.0, 9.0
class Patient:
def __init__(self, pid, ptype):
self.pid = pid
self.ptype = ptype
self.time_arrived = None
self.time_admitted = None
self.time_discharged = None
def generate_arrivals(env, ptype):
while True:
global counter
counter += 1
patient = Patient(counter, ptype)
env.process(perform_treatment(env, patient))
# sample arrivals
if patient.ptype == 'A':
interarival_time = exponential(scale=mean_iat_a)
elif patient.ptype == 'B':
interarival_time = exponential(scale=mean_iat_b)
else:
interarival_time = exponential(scale=mean_iat_c)
yield env.timeout(interarival_time)
def perform_treatment(env, patient):
patient.time_arrived = env.now
print(f'Patient {patient.pid} - {patient.ptype} - arrived at {patient.time_arrived}')
with beds.request() as req:
yield req
patient.time_admitted = env.now
print(f'Patient {patient.pid} - {patient.ptype} - admitted at {patient.time_admitted}')
# sample duration of stay
if patient.ptype == 'A':
stay_duration = lognormal(mean=normal_mean_a, sigma=normal_stdev_a)
elif patient.ptype == 'B':
stay_duration = lognormal(mean=normal_mean_b, sigma=normal_stdev_b)
else:
stay_duration = lognormal(mean=normal_mean_c, sigma=normal_stdev_c)
yield env.timeout(stay_duration)
patient.time_discharged = env.now
print(f'Patient {patient.pid} - {patient.ptype} - discharged at {patient.time_discharged}')
env = simpy.Environment()
beds = simpy.Resource(env, capacity=total_beds)
env.process(generate_arrivals(env, 'A'))
env.process(generate_arrivals(env, 'B'))
env.process(generate_arrivals(env, 'C'))
env.run(until=run_length)
这种方法的问题在于,每个类别的患者在其各自流程开始时都会创建(它总是在时间 = 0 时创建每个类别的患者 1、2 和 3),但它不会反映真实场景:
Patient 1 - A - arrived at 0
Patient 2 - B - arrived at 0
Patient 3 - C - arrived at 0
Patient 1 - A - admitted at 0
Patient 2 - B - admitted at 0
Patient 3 - C - admitted at 0
Patient 1 - A - discharged at 0.04165029350880402
Patient 4 - A - arrived at 0.6503311494436321
Patient 4 - A - admitted at 0.6503311494436321
Patient 4 - A - discharged at 0.6626671650563922
Patient 5 - B - arrived at 0.6868621026906724
.
.
etc
到目前为止,我一直在考虑使用:
- child 类 存储类别特定常量和
- 通过
numpy.random.multinomial()
以相同的概率随机决定生成哪种患者的单个过程。
import simpy
from numpy.random import exponential, lognormal, multinomial
counter = 0
total_beds = 5
run_length = 10
ptypes = ['A', 'B', 'C']
probvals = [1.0 / len(ptypes) for _ in ptypes]
class Patient:
def __init__(self, pid, ptype):
self.pid = pid
self.ptype = ptype
self.time_arrived = None
self.time_admitted = None
self.time_discharged = None
class TypeA(Patient):
def __init__(self, pid, ptype):
super().__init__(pid, ptype)
self.mean_iat = 1.0
self.normal_mean = 4.0
self.normal_stdev = 7.0
class TypeB(Patient):
def __init__(self, pid, ptype):
super().__init__(pid, ptype)
self.mean_iat = 2.0
self.normal_mean = 5.0
self.normal_stdev = 8.0
class TypeC(Patient):
def __init__(self, pid, ptype):
super().__init__(pid, ptype)
self.mean_iat = 3.0
self.normal_mean = 6.0
self.normal_stdev = 9.0
def generate_arrivals(env):
while True:
global counter
counter += 1
ptype = ptypes[multinomial(n=1, pvals=probvals).argmax()]
# From here is where I'm stuck
# Can't understand how to drive the correct object instantiation
# to replace the if-elif-else from the previous example
patient = Patient(counter, ptype)
# Not sure of the logic from here on out
env.process(perform_treatment(env, patient))
interarival_time = exponential(scale=patient.mean_iat)
yield env.timeout(interarival_time)
def perform_treatment(env, patient):
patient.time_arrived = env.now
print(f'Patient {patient.pid} - {patient.ptype} - arrived at {patient.time_arrived}')
with beds.request() as req:
yield req
patient.time_admitted = env.now
print(f'Patient {patient.pid} - {patient.ptype} - admitted at {patient.time_admitted}')
# Again, how do I replace the if-elif-else from the previous example
stay_duration = lognormal(mean=patient.normal_mean, sigma=patient.normal_stdev)
yield env.timeout(stay_duration)
patient.time_discharged = env.now
print(f'Patient {patient.pid} - {patient.ptype} - discharged at {patient.time_discharged}')
env = simpy.Environment()
beds = simpy.Resource(env, capacity=total_beds)
env.process(generate_arrivals(env))
env.run(until=run_length)
但是,我似乎无法理解如何使用 Simpy 来完成它。对我的方法或替代想法的任何意见将不胜感激!
注意: 我知道使用 numpy.random.multinomial()
会导致一次只生成一种患者,但这可能完全是一个不同的问题。
在你的第一个代码中,你能否移动你的 gen patient 代码,你能否将你的超时移到循环的顶部。当然这意味着你不会在时间 0
得到任何病人您在 env.run 之前启动的每个进程都在时间 0 开始,并且在第一个 yield 之前发生的所有事情都在时间 0 发生。调用 env.timeout 不会影响其他进程。我想到了每个进程和它自己的线程。所以当你的程序调用env.run时。它抓住你的一个进程并创建一个病人,然后在 yield env 等待。 timeout(),然后它会抓取第二个进程,仍然在时间 0,并创建一个患者并在 yield 处暂停。等...等...在短时间内不会在过程中移动,直到它达到产量。这有帮助吗? – 迈克尔 11 小时前 删除 当流程中的第一行是 yield env.timeout() 时,在超时完成并且时间已更新之前什么都不会发生。它具有在进程应该启动时进行调度的效果