粒子群算法尝试解决整数规划问题(效果不好的尝试)

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 约束条件问题

粒子群算法尝试解决整数规划问题(效果不好的尝试)

约束条件太复杂的话,使用随机数更新的粒子位置很难满足约束条件