数模准备过程中,写了这种运筹学仿真的代码,虽然自己选了C题没有用到,但考虑到市面上存在的仿真代码较少,聊以为分享。
文档介绍
本文档使用了Python的离散事件仿真库对于排队论模型进行了仿真
仿真的主要目的是提供个性化定制,如对分布的设定,对排队规则的设定等。通过蒙特卡洛模拟得到复杂规则下难以得到的数值解。
本文档提供了:
基础排队模型仿真
Erlang分布实现
通用分布函数适配器
工具库
库依赖
from numpy.random import *
from simpy import *
高阶函数随机数生成器
输入:分布函数,单一参数(多参数请柯里化)
输出:随机数
def rng(dis,param):
"""random number generator"""
def generate():
return dis(lam=param,size=1)[0]
return generate
Erlang分布函数:
输入:阶数
输出:k阶erlang分布函数
def erlang(k):
"""由k个指数分布拟合"""
def exp2erlang(lam,size):
res=[]
for n in range(size):
k_poisson= exponential(lam/k,size=k)
sum=0
for x in k_poisson:
sum = sum + x
res.append(sum)
return res
return exp2erlang
测试,计算分布期望
x=rng(erlang(10),10)
sum=0
for i in range(10000):
sum= sum+x()
print(sum/10000)
结果为9.99565983119657,说明函数正确
FIFO队列模型
#典型银行模型:FIFO
def bankSample(X,Y,Z,A,B,EX):
"""
银行排队服务例子
情景:
一个柜台对客户进行服务, 服务耗时, 客户等候过长会离开柜台
%X 表示时间间隔分布
%Y 表示服务时间的分布
%Z 表示服务台的个数
%A 表示系统的容量,此处特殊化为客户的耐心时间分布
%B 表示顾客数
%以上参数必须有界,受到计算机精度限制,可以使用大常数近似无穷
%C 表示服务规则,请修改函数
%EX 传递了银行储蓄额的分布
"""
#加入随机种子是为了对比模型的变化
seed(2)
def source(env, number, interval,counter):
"""生成客户"""
for i in range(number):
c = customer(env, '客户%04d' % i, counter, time_in_bank=Y(),account=EX())
env.process(c)
yield env.timeout(interval)
#成功服务的客户
SUCC=0
#成功客户等待时间
WAIT=0
#成功客户逗留时间
STAY=0
#业务额
AMT=0
def customer(env, name, counter, time_in_bank,account):
nonlocal WAIT
nonlocal SUCC
nonlocal STAY
nonlocal AMT
"""顾客服务与离开仿真"""
arrive = env.now
#print('%7.4f %s: 到达' % (arrive, name))
with counter.request() as req:
patience = A()
# 直到到达或者失去耐心
results = yield req | env.timeout(patience)
wait = env.now - arrive
if req in results:
# 到达
WAIT=WAIT+wait
STAY=STAY+time_in_bank
AMT= AMT + account
#print('%7.4f %s:等待%6.3f' % (env.now, name, wait))
yield env.timeout(time_in_bank)
SUCC=SUCC+1
#print('%7.4f %s:服务完成' % (env.now, name))
else:
# We reneged
pass
#print('%7.4f %s:等待%6.3f后离开' % (env.now, name, wait))
# 初始化环境
print('排队问题仿真')
env = Environment()
# 开始协程
counter = Resource(env, capacity=Z)
env.process(source(env, B, X(), counter))
env.run()
print("总服务人数:{0:n}人".format(SUCC))
print("总营业额:{0:n}元".format(AMT))
print("总计失去: {0:n}名客户".format(B-SUCC))
print("损失率为: {0:n}%".format((B-SUCC)/B*100))
print("平均等待时间:{0:n}".format(WAIT/SUCC) )
print("平均耗费时间:{0:n}".format(STAY/SUCC) )
我们以下列参数作为输入
#间隔分布
X=rng(erlang(3),3)
#服务时间分布
Y=rng(erlang(3),10)
#耐心时间分布
A=rng(erlang(3),3)
#业务额分布正态
def normaltocurry(s):
def normalcurry(lam,size):
return normal(lam,s,size=size)
return normalcurry
EX=rng(normaltocurry(200),1000)
bankSample(X,Y,3,A,1000,EX)
输出的结果为:
排队问题仿真
总服务人数:417人
总营业额:409903元
总计失去: 583名客户
损失率为: 58.3%
平均等待时间:1.8828
平均耗费时间:10.0787
营业额优先队列模型
然后,我们转变一下模型,变成营业额越高越优先的队列
#银行模型·ELite:优先队列
def eliteBankSample(X,Y,Z,A,B,EX):
"""
银行排队服务例子
情景:
一个柜台对客户进行服务, 服务耗时, 客户等候过长会离开柜台
%X 表示时间间隔分布
%Y 表示服务时间的分布
%Z 表示服务台的个数
%A 表示系统的容量,此处特殊化为客户的耐心时间分布
%B 表示顾客数
%以上参数必须有界,受到计算机精度限制,可以使用大常数近似无穷
%C 表示服务规则,请修改函数
%EX 传递了银行储蓄额的分布
"""
#加入随机种子是为了对比模型的变化
seed(2)
def source(env, number, interval,counter):
"""生成客户"""
for i in range(number):
c = customer(env, '客户%04d' % i, counter, time_in_bank=Y(),account=EX())
env.process(c)
yield env.timeout(interval)
#成功服务的客户
SUCC=0
#成功客户等待时间
WAIT=0
#成功客户逗留时间
STAY=0
#业务额
AMT=0
def customer(env, name, counter, time_in_bank,account):
nonlocal WAIT
nonlocal SUCC
nonlocal STAY
nonlocal AMT
"""顾客服务与离开仿真"""
arrive = env.now
#print('%7.4f %s: 到达' % (arrive, name))
#以业绩作为优先级,priority越小,优先级越大,
with counter.request(priority = 1/account) as req:
patience = A()
# 直到到达或者失去耐心
results = yield req | env.timeout(patience)
wait = env.now - arrive
if req in results:
# 到达
WAIT=WAIT+wait
STAY=STAY+time_in_bank
AMT= AMT + account
#print('%7.4f %s:等待%6.3f' % (env.now, name, wait))
yield env.timeout(time_in_bank)
SUCC=SUCC+1
#print('%7.4f %s:服务完成' % (env.now, name))
else:
# We reneged
pass
#print('%7.4f %s:等待%6.3f后离开' % (env.now, name, wait))
# 初始化环境
print('排队问题仿真')
env = Environment()
# 开始协程
counter = PriorityResource(env, capacity=Z)
env.process(source(env, B, X(), counter))
env.run()
print("总服务人数:{0:n}人".format(SUCC))
print("总营业额:{0:n}元".format(AMT))
print("总计失去: {0:n}名客户".format(B-SUCC))
print("损失率为: {0:n}%".format((B-SUCC)/B*100))
print("平均等待时间:{0:n}".format(WAIT/SUCC) )
print("平均耗费时间:{0:n}".format(STAY/SUCC) )
以相同的参数测试
结果为:
排队问题仿真
总服务人数:432人
总营业额:450145元
总计失去: 568名客户
损失率为: 56.8%
平均等待时间:1.28862
平均耗费时间:9.69799
总结
可以看出,在加入了上述充满着歧视与不公平的规则之后, 人均营业额上升,并且等待时间和耗费时间都有所下降 即:富人和银行获得了利益,富人节约了自己的时间,银行增加了业绩sjtuzwj/OperationalResearchModelinggithub.com
内部含网络图/决策论等算法。