Python -Simpy 4.0.1-环境中多种输入
我一直在研究一个问题,我必须在一个simpy 4.0.1计划中模拟患者,该计划具有多种患者(例如“ A”,“ B”和“ C”)。患者根据numpy.random.partential()
和“占用床”(simpy Resources)在中心基于numpy.random.landom.lognormal()< /代码>。每种患者类型都有不同的值以控制此抽样。这是一个简单的FIFO过程,无需优先考虑,患者只是以不同的速度到达。
我尝试的第一种方法是为每个类别的患者创建3个过程,然后让小调子处理他们的一代:
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)
这种方法的问题是,在各自过程开始时都有每个类别的患者(它总是创造患者1,2&amp;在时间= 0的每个类别中的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
到目前为止,我一直在玩:用于使用
- 特定类别的常数
- 通过
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()
一次仅会产生一种患者,但这可能完全是一个不同的问题。
I've been working on a problem where I must simulate patients at a treatment centre in a Simpy 4.0.1 program, that has multiple categories of patients (say "A", "B" and "C"). The patients "arrive" based on timeouts generated from numpy.random.exponential()
and "occupy a bed" (Simpy resources) at the centre based on numpy.random.lognormal()
. Each patient type has a different set of values to control this sampling. This is a simple FIFO process and has no priority involved, the patients simply arrive and stay at different rates.
The first way I tried was to create 3 processes for each category of patient, and let Simpy handle their generation:
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)
The problem with this approach was that there is a patient of each category created at the beginning of their respective process (it always creates patients 1, 2 & 3 of each category at time = 0), which doesn't reflect a real-world scenario:
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
So far, I've been toying with the idea of using:
- child classes to store the category-specific constants and
- a single process to randomly decide what kind of patient is generated, via
numpy.random.multinomial()
with equal probabilities.
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)
However, I can't seem to understand how to go about it using Simpy. Any inputs on my approach, or alternative ideas would be greatly appreciated!
Note: I'm aware that using numpy.random.multinomial()
results in only a single kind of patient being generated at a time, but that's probably a different question altogether.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在您的第一个代码中,您可以移动Gen患者代码吗?您可以将超时移至循环的顶部吗?当然,这意味着您不会在时间
0开始在每个过程开始之前启动的每个过程。过程。我想到每个过程及其自己的线程。因此,当您的程序致电Env.Run。它抓住了您的一个过程,创建患者,然后在收益率上等待。超时(),然后抓住第二个过程,仍处于时间0,并创建一个患者并以产量的暂停。 ect ... ect ...在短时间内不会在一个过程中移动,直到达到产量为止。这有帮助吗? -
迈克尔
11小时前删除
当该过程中的第一行是收益and Env.TimeOut()直到超时完成并更新时间之前,什么都不会发生。它具有调度的效果
in your first code, can you move your gen patient code, can you move your timeout to the top of the loop. Of course this means you would not get any patients at time 0
every process you start before the env.run starts at time 0, and everything that happens before the first yield happens at time 0. calling a env.timeout does not affect the other process. I think of each process and its own thread. So when your program calls env.run. It grabs one of your process and creates a patient and then waits at the yield env. timeout(), it then grabs the second process, still at time 0, and creates a patient and pauses at the yield. ect... ect... in short time does not move in a process until it gets to a yield. Does this help? –
Michael
11 hours ago Delete
when the first line in the process is a yield env.timeout() nothing happens until the timeout is done and the time has been updated. It has the effect of scheduling when the process should star