粒子群算法尝试解决整数规划问题(效果不好的尝试)
1问题描述
某厂每日8小时的产量不低于1800件.为了进行质量控制,计划聘请两种不同水平的检验员.且每种检验员的日产量不高于1800件.一级检验员的标准为:速度25件/小时,正确率98%,计时工资4元/小时;二级检验员的标准为:速度15件/小时,正确率95%,计时工资3元/小时.检验员每错检一次,工厂要损失2元.为使总检验费用最省,该工厂应聘一级、二级检验员各几名?
2 分析问题
设需要一级和二级检验员的人数分别是x1 x2,则一天要付给检验员的费用是:
8*4*x1+8*3*x2=32x1+24x2
一天中因为检验员失误所造成的损失是:
(8*25*0.02*x1+8*15*0.05*x2)*2=8x1+12x2
约束条件:
8*25*x1+8*15*x2>=1800
8*25*x1<=1800
8*15*x2<=1800
X1>=0,x2>=0
即:
3 算法设计
li
粒子群初始化为二维数组,种群大小的行,2为列数,由所求的自变量为X1 和X2所得。
同样,粒子速度也为二维数组
粒子群算法执行过程中,加入约束条件检验函数入下:
代码:python语言
_date_ = '2019/5/27 20:16' # -*- coding:utf-8 -*- import numpy as np import time import matplotlib.pyplot as plt import math start = time.clock() def getweight(): # 惯性权重 weight = 1 return weight def getlearningrate(): # 分别是粒子的个体和社会的学习因子,也称为加速常数 # lr = (0.1,1.2) lr = (0.49445, 1.49445) return lr def getmaxgen(): # 最大迭代次数 maxgen = 20 return maxgen def getsizepop(): # 种群规模 sizepop = 20 return sizepop def getrangepop(i): # 粒子的位置的范围限制,x、y方向的限制相同 # rangepop = (-2*math.pi , 2*math.pi) #rangepop = (-2,2) if (i ==0): rangepop = (0, 9) else: rangepop = (0, 15) return rangepop def getrangespeed(): # 粒子的速度范围限制 # rangespeed = (-0.5,0.5) rangespeed = (-5, 5) return rangespeed def func(x): # print("x的值和func") # print(x) if(issuitable(x)==0): y=10000 return y # x输入粒子位置 # y 粒子适应度值,求得最小函数值 y =40*x[0]+36*x[1] # print(y) return y #是否符合约束条件 def issuitable(x): # print("检验函数") if(5*x[0]+3*x[1]>=45): if((x[0]<=9.0)&(x[0]>=0.0)): if ((x[1] <=15.0)&( x[1] >= 0.0)): return 1 return 0 def initpopvfit(sizepop): pop = np.zeros((sizepop,2)) v = np.zeros((sizepop,2)) fitness = np.zeros(sizepop) for i in range(sizepop): flag = 0 while True: for j in range(2): pop[i][j] = (np.random.rand() - 0.5) * getrangepop(j)[1]*2 pop[i][j] = round(pop[i][j]) pop[pop < getrangepop(j)[0]] = getrangepop(j)[0] pop[pop > getrangepop(j)[1]] = getrangepop(j)[1] v[i][j] = np.random.rand()-0.5 # 计算这个粒子的适应度 flag = issuitable(pop[i]) if flag == 1: fitness[i] = func(pop[i]) break # print("初始fitness") # print(fitness) return pop,v,fitness def getinitbest(fitness,pop): # 群体最优的粒子位置及其适应度值 gbestpop,gbestfitness = pop[fitness.argmin()].copy(),fitness.min() #个体最优的粒子位置及其适应度值,使用copy()使得对pop的改变不影响pbestpop,pbestfitness类似 pbestpop,pbestfitness = pop.copy(),fitness.copy() # print("全局最优") # print(gbestpop) # print(gbestfitness) return gbestpop,gbestfitness,pbestpop,pbestfitness w = getweight() # 获取惯性权重 lr = getlearningrate() #分别是粒子的个体和社会的学习率 maxgen = getmaxgen() # 获得最大迭代次数 sizepop = getsizepop() # 获取种群规模 # rangepop = getrangepop() # 粒子的位置的范围限制,x、y方向的限制相同 rangespeed = getrangespeed() # 粒子的速度范围限制 pop,v,fitness = initpopvfit(sizepop) #初始化种群 gbestpop,gbestfitness,pbestpop,pbestfitness = getinitbest(fitness,pop) # 群体最优的粒子位置及其适应度值,个体最优的粒子位置及其适应度值 result = np.zeros(maxgen) before = np.zeros(2) beforev = np.zeros(2) #记录粒子的自变量的值 #返回来一个maxgen大小的一维数组; for u in range(maxgen): for i in range(sizepop): flag = 0 for o in range(2): before[o] = pop[i][o] beforev=pop[i][o] while True: for j in range(2): v[i][j] = v[i][j]+lr[0] * np.random.rand() * (pbestpop[i][j] - pop[i][j]) + lr[1] * np.random.rand() * (gbestpop[j] - pop[i][j]) v[v < rangespeed[0]] = rangespeed[0] v[v > rangespeed[1]] = rangespeed[1] # 粒子位置更新,需要检查粒子的约束条件是否符合 pop[i][j] = v[i][j] + pop[i][j] pop[i][j]=round(pop[i][j]) # int是向下取整 pop[pop < getrangepop(j)[0]] = getrangepop(j)[0] pop[pop > getrangepop(j)[1]] = getrangepop(j)[1] flag = issuitable(pop[i]) if flag == 1: break else: pop[i] = before v[i]=beforev #适应度更新 for j in range(sizepop): fitness[j] = func(pop[j]) for j in range(sizepop): if ((fitness[j] < pbestfitness[j])): pbestfitness[j] = fitness[j] pbestpop[j] = pop[j].copy() if(pbestfitness.min() < gbestfitness): gbestfitness = pbestfitness.min() gbestpop = pop[pbestfitness.argmin()].copy() result[u] = gbestfitness print(result) plt.plot(result) plt.show() end = time.clock() print("time") print((end-start)*1000.0)
由于自变量的取值空间较小,可用穷举法进行比较:
穷举法代码:
_date_ = '2019/5/28 7:43' #利用穷举计算整数规划的值 import numpy as np import time start = time.clock() num=0 max=0 m=0 n=0 b = np.zeros((160,3)) for x1 in range(10): for x2 in range(16): if (5 * x1 + 3 * x2>= 45): b[num][0]=x1 b[num][1] = x2 b[num][2] = 40*x1+36*x2 num+=1 print("num") print(num) min=b[0][2] m=b[0][0] n=b[0][1] for i in range(num): # print("b") # print(b) # print("b[num][2]") # print(b[0][2]) if(b[i][2]<min): min=b[i][2] m=b[i][0] n=b[i][1] print(min) print(min) print(m) print(n) end = time.clock() print("time") print((end-start)*1000.0) #ms为单位 对比结果:
用时竟然比穷举法还长好多,最后,尝试失败
可以找到使得粒子位置更符合约束条件的方法效果应该会好很多
出现的问题:
1 速度区间问题
由用户设定用来限制粒子的速度
区间太小加上约束条件容易陷入死循环
2 约束条件问题
约束条件太复杂的话,使用随机数更新的粒子位置很难满足约束条件