遗传算法到变异过程代码实现

import math
import random
from random import sample
import numpy as np
from numpy import *
import geatpy as ea
import xlrd
import pysnooper


##已知数据
q1='F:\共享车选址调度\共享汽车数据\候选点之间的OD(13).xlsx'
T1='F:\共享车选址调度\共享汽车数据\候选点之间的最短期望时间Tik(13).xlsx'
wt1='F:\共享车选址调度\共享汽车数据\需求中心到备选点的步行时间(50行13列).xlsx'
D1='F:\共享车选址调度\共享汽车数据\每个需求中心的需求量(50网格).xlsx'
# ####excel转为矩阵
def excel_to_matrix(path,a):  #路径,sheet
    table = xlrd.open_workbook(path).sheets()[a]#获取第一个sheet表
    row = table.nrows  # 行数
    col = table.ncols  # 列数
    datamatrix = np.zeros((row, col))#生成一个nrows行ncols列,且元素均为0的初始矩阵
    for x in range(col):
        cols = np.matrix(table.col_values(x))  # 把list转换为矩阵进行矩阵操作
        datamatrix[:, x] = cols # 按列把数据存进矩阵中
    return datamatrix
q=excel_to_matrix(q1,0)
T=excel_to_matrix(T1,0)
wt=excel_to_matrix(wt1,0)
D=excel_to_matrix(D1,1)  # 多维数组,50行1列
# #############参数##########################
Cs=1*10
Cp=12*10
Cv=56*10
Ce=6
M=10000
alpha=0.8
beta=0.5
gama=2
I=13
J=50
Pmax=100
w1=50
H =500000  # 成本的最大值
##########################################
##距离衰减
s=zeros((J, I))  # 创建一个J*I的零矩阵,矩阵这里zeros函数的参数是一个tuple类型(J,I)
for i in range(I):
    for j in range(J):
        if wt[j,i]<w1:
            a=-(wt[j,i])**4+w1**4
            b=(w1**4)*(math.exp((wt[j,i]/40)**3))
            s[j,i]=a/b
        elif wt[j,i]>w1:
            s[j,i]=0
## qik/qi
n=zeros((J, I))
for i in range(I):
    for k in range(I):
        if sum(q[i])>0:  #每一行的和
            n[i,k]=q[i,k]/sum(q[i])
        else:
            n[i,k]=0
'''1.目标函数'''
def objection(X,P,V,z):
    z0=np.array(z).reshape(J,I)  #列表转一维数组,转多维数组
    for i in range(I):
        Ti = T[i, :]  # 多维数组,第i行
        ni = n[i, :]
        ui= [sum(D[:,0]*z0[:,i]*s[:,i]) for i in range(I)] # 输出为一个列表,其中含有13个元素,表示分布从13个备选站点出发的租车辆
        # ob = [Cs * X[i] + Cp * P[i] + Cv * V[i] + Ce * sum(Ti * ni) * ui[i] for i in range(I)]  # 输出为一个列表,其中含有13个元素,每个元素对应一个站点的成本
        obj=sum([Cs * X[i] + Cp * P[i] + Cv * V[i] + Ce * sum(Ti * ni) * ui[i] for i in range(I)])  #输出结果为总成本,约29万
    return obj

'''2.实数编码'''
def code():
    Chrom = []
    X_0 = np.random.randint(0, 2, I)  # 随机产生13个只含0,1元素的列表,13为初始种群的个数

    P_0 = np.random.randint(2, 101, I)  # 随机产生13个0到100中的正整数的列表
    V_0 = np.random.randint(1, 81, I)  # 随机产生13个0到80中的正整数的列表.80=100*alpha
    z0 = np.random.random((J, I))  # J=50,I=30,50行13列的二维数组
    for i in range(len(X_0)):
        if X_0[i] == 0:
            P_0[i], V_0[i], z0[:, i] = 0, 0, 0  # 如果站点没有被选中,X_0[i] = 0,那么V,P,z都为0

        else:
            P_0[i], V_0[i], z0[:, i] = P_0[i], np.random.randint(1, math.ceil(alpha*P_0[i])), z0[:,
                                                                             i]  # 如果站点被选中,X_0[i] = 1,那么V,z不变,P=alpha*V
    z_0 = z0.flatten()  # 转化为一维数组,按行转化
    u_0 = [sum(D[j, 0] * z_0[I * j + i] * s[j, i] * n[i, k] for j in range(J)) for i in range(I) for k in
           range(I)]  # 含有I*I=169个元素,uik
    Chrom.extend(X_0)
    Chrom.extend(P_0)
    Chrom.extend(V_0)
    Chrom.extend(z_0)
    Chrom.extend(u_0)
    return Chrom

'''3.区分各个变量'''
def Chrom_to_var(Chrom):
    X=Chrom[:I]  #前13个元素为X
    P=Chrom[I:2*I]  # 共13个元素
    V=Chrom[2*I:3*I]  # 共13个元素
    z=Chrom[3*I:3*I+I*J]  # 共50*13个元素
    u=Chrom[3*I+I*J:]  # 共13*13个元素
    return X,P,V,z,u

'''4.站点约束'''
def station_feasible(Chrom):
    X,P,V,z,u=Chrom_to_var(Chrom)
    g1 = [P[i]-M*X[i] for i in range(I)]  # I个约束
    g2 = [X[i]-P[i] for i in range(I)]  # I个约束
    g3 = [V[i]-alpha*P[i] for i in range(I)]  # I个约束
    g4 = [P[i]-Pmax for i in range(I)]  # I个约束
    g_0 = g1 + g2 + g3 + g4  # 将前4I个约束放到同一个列表中
    # print(g1,g2,g3,g4,g)
    num_cons = I * I * I * I
    rhs = [0] * num_cons  # 输出为有4I个元素的列表,每个元素都是0
    cons_0 = [g_0[m] <= rhs[m] for m in range(len(rhs))]  # 前面将约束写为<=0的形式,这里进行判断,输出为[True,False……]
    return g_0,cons_0

'''5.需求约束'''
def demand_feasible(Chrom):
    X,P,V,z,u=Chrom_to_var(Chrom)
    g5 =[z[I*j+i]-X[i] for i in range(I) for j in range(J)]  # J*I个约束
    # g5_n = np.array(g5).reshape(J, I)  # 将一维列表转化为J行I列的数组
    # g5_c = [sum(g5_n[:, i]) for i in range(I)]  # 对每一列求和,得到每个染色体(每个站点)对应的约束,输出为含有I个元素的列表
    g6 =[sum(z[I * j + i] for i in range(I))-1 for j in range(J)]  # J个约束
    g7 =[sum(D[j,0]*z[I*j+i] for i in range(I))-D[j,0] for j in range(J)]  # J个约束
    g8 =[sum(D[j,0]*z[I*j+i] for j in range(J))-P[i] for i in range(I)]  # I个约束
    g9 =[beta*sum(D[j,0] for j in range(J))-sum(sum(D[j,0]*z[I*j+i]*s[j,i] for i in range(I)) for j in range(J))]  # 1个约束
    # g10 =[sum(D[j,0]*z[I*j+i]*s[j,i]*n[i,k] for j in range(J))-u[I*i+k] for i in range(I) for k in range(I)]  # I*I个约束
    # g11 =[u[I*i+k]-sum(D[j,0]*z[I*j+i]*s[j,i]*n[i,k] for j in range(J)) for i in range(I) for k in range(I)]  # I*I个约束
    g12 =[sum(u[I*i+k] for k in range(I))-V[i] for i in range(I)]  # I个约束
    g13 =[sum(u[I*i+k] for i in range(I) for k in range(I))*0.657+11.89-sum(V[i] for i in range(I))]  # 1个约束
    g_1 = g5+g6+g7+g8+g9+g12+g13  # 将前面所以约束放到同一个列表中,1116个元素
    g_pos = sum([abs(i) for i in g_1])  # 将g_1中的元素转化为正值并求和
    num_cons = I*J+J+J+I+1+I+1
    rhs = [0] * num_cons  # 输出为有I*J+J+J+I+1+I*I+I*I+I+1个元素的列表,每个元素都是0
    cons_1 = [g_1[m] <= rhs[m] for m in range(len(rhs))]  # 前面将约束写为<=0的形式,这里进行判断,输出为[True,False……]
    return g_1,g_pos,cons_1
'''6.产生初始种群'''
def initial_pop(Nind):  # Nind为种群数量
    pop=[]
    i=0
    while i<Nind:
        IND=code()
        pop.append(IND)
        i += 1
    return pop  # 输出为含有Nind个染色体的种群,是一个列表

'''7.计算适应度'''
def get_fitness(pop, Nind,C,c):  # C是一个足够大的数,目标函数的最大估计,Nind为种群数量
    fit=[]
    for i in range(Nind):
        X=Chrom_to_var(pop[i])[0]
        P = Chrom_to_var(pop[i])[1]
        V = Chrom_to_var(pop[i])[2]
        z = Chrom_to_var(pop[i])[3]
        H=objection(X,P,V,z)
        if all(demand_feasible(pop[i])[2]) is True:
            fitness=C-H # Z为目标函数
        else:
            fitness=C-H-c*demand_feasible(pop[i])[1] #g(x)为约束条件,c为正值常数
        fit.append(fitness)  # 将每次循环的结果存入列表中,输出为[89688.98555388054, 144668.3419467736, 97700.61376721218, 173935.77171023752, 160989.79620219418]
    return fit
'''8.适应度排序'''
def fit_sort(fit):
    fit2 = fit[:]   # 通过分片操作将列表FitnV_l的元素全部拷贝给FitnV2,产生一个新副本,不改变fit的适应度排序,便于后面染色体的索引
    fit2.sort(reverse=True)  # 适应度降序排序,产生一个排序好的副本,同时保持原有列表不变
    return fit2
'''9.得到精英个体'''
def get_elite(pop,fit,fit2,eli_n):
    Se_eli =fit2[:eli_n]  #选择前eli_n个个体直接进入子代
    See_ind = [fit.index(i) for i in Se_eli]  #得到被选择个体的索引
    pop_e=[]
    for i in See_ind:
        pop_e.append(pop[i])
    return pop_e  # 返回值为直接进入子代的精英个体

'''10.自然选择:轮盘赌'''
def selection(pop,fit,Nsel):
    # USe_eli = fit2[eli_n:]  # 精英选择中未被选择的个体
    USe_eli1=np.array(fit).reshape(7,1)  # 转化为多维数组,N为种群数量
    se_ind =ea.rws(USe_eli1,Nsel) # 得到被选择个体的索引, Nsel被选择个体的数目
    pop_s = []
    for i in se_ind:
        pop_s.append(pop[i])
    return pop_s  # 列表嵌套列表,外列表内有Nsel个元素,每个元素代表一个个体,内列表有I+I+I+J*I+I*I个元素,每个元素代表一个基因

# pop_1 = selection(pop,fit,Nsel)  # 参与交叉的个体
# print(pop_1)

'''11.交叉:线性交叉'''
# @pysnooper.snoop()
def crossover(pop_s,pc):
    j = 0
    while j <= 2:
        chrom = sample(pop_s, 2)  # 抽取pop_1中的两个个体染色体进行交叉。[[],[]]
        # print(chrom)
        chrom_ind = [pop_s.index(i) for i in chrom]  # 得到进行交叉的染色体在pop_1中的索引
        # n_chorm=pop_1[row_rand_array[2:]]
        c_point1 = random.randint(0, len(chrom[0])-1)
        c_point2 = random.randint(0, len(chrom[0])-1)  # 随机得到两个数,用于确定交叉的起止点
        if c_point1 <= c_point2:
            s_point = c_point1
            e_point = c_point2
        else:
            s_point = c_point2  # 小的数作为起点
            e_point = c_point1  # 大的数作为终点
        # print(s_point, e_point)
        r = random.random()
        if r <= pc:  # 如果小于交叉概率
            pop_s[chrom_ind[0]] = pop_s[chrom_ind[0]]  # 两个染色体不进行交叉操作
            pop_s[chrom_ind[1]] = pop_s[chrom_ind[1]]
            # print(new_C)
        else:
            a = random.random()
            b = random.random()
            # print(a, b)
            chrom_n1 = chrom[0]  # 父代1
            chrom_n2 = chrom[1]  # 父代2
            for i in range(s_point, e_point + 1):  # 遍历每个交叉点
                Ge1 = chrom[0][i]  # 父代1交叉前的基因
                Ge2 = chrom[1][i]
                if 0<=i<=3*I-1:  #如果进行交叉的基因是前3*I个,前3*I个基因为整数型,要进行判断
                    Ge1 = int(Ge2 + a * (Ge1 - Ge2))
                    Ge2 = int(Ge1 + b * (Ge2 - Ge1)) # 交叉后的基因
                else:  # 后面的基因是浮点型
                    Ge1 = Ge2 + a * (Ge1 - Ge2)
                    Ge2 = Ge1 + b * (Ge2 - Ge1)
                # print(Ge1, Ge2)
                chrom_n1[i] = Ge1
                chrom_n2[i] = Ge2 #更新染色体
                for chrom_c in [chrom_n1,chrom_n2]:  #对交叉后的两个染色体分别进行判断是否满足基本约束条件
                    for k in range(I):
                        if chrom_c[k] == 0:  #如果X=0,站点没有被选中
                            chrom_c[I + k] = 0  # 对应的P=0
                            chrom_c[2 * I + k] = 0  # 对应的V=0
                            for g in range(0, J ):
                                chrom_c[(g+3) * I + k] = 0 # 对应的z=0
                            for t in range(I):
                                chrom_c[(3 + J + k) * I + t] = 0
                        else:
                            chrom_c[I + k] = chrom_c[I + k]  # 对应的P=交叉后的结果,不改变
                            chrom_c[2 * I + k] = np.random.randint(1, math.ceil(alpha*chrom_c[I + k])) # 对应的V=alpha*P
                               # 对应的z=0
                            for g in range(0, J ):
                                chrom_c[(g+3) * I + k] = chrom_c[(g+3) * I + k]  # 对应的z=交叉后的结果,不改变
                            for t in range(I):  # u与z的对应关系
                                chrom_c[(3 + J + k) * I + t] = [sum(D[j, 0] * chrom_c[(j+3) * I + k] * s[j, k] * n[k, t] for j in range(J))]
                            # print(chorm_n1, chorm_n2)
                            # print(chorm_n1, chorm_n2)  # 注意缩进,只要最后每个点交叉后最终的迭代结果
            pop_s[chrom_ind[0]] = chrom_n1
            pop_s[chrom_ind[1]] = chrom_n2  # 更新整个种群,将交叉后的染色体存入种群中
        j += 2
    return pop_s
# @pysnooper.snoop()
def mutate(pop_s,pm):
    j = 0
    while j <= 3:
        px = len(pop_s)  # 种群中染色体的数目
        py = len(pop_s[0])  #每个染色体中基因的数目
        im = random.randint(0, px - 1)  # im为进行变异的染色体的索引
        # chrom_m = pop_1[im]  # 进行变异的染色体
        # 判断每条染色体的每个基因是否需要变异
        for i in range(py):
            if (random.random() <= pm):
                pop_s[im][i] = pop_s[im][i]  # 如果随机值小于变异概率,则不需变异,基因不改变
            else:
                if 0 <= i <=  I-1:  # 如果进行变异的基因是X,前I个
                    if pop_s[im][i]==0:  # 如果该基因取值为0
                        pop_s[im][i] = 1  # 变异后的基因为1
                        pop_s[im][I+i]= random.randint(2, 101)  # 对应的P值也不等于0,在取值范围中随机产生一个值
                        pop_s[im][2*I+i]=random.randint(1,math.ceil(alpha*pop_s[im][I+i]))  # V=alpha*P 向上取值
                        for g in range(0, J):
                            pop_s[im][(g + 3) * I + i] =random.uniform(0, 1)  #对应的z值
                        for t in range(I):  # u是与z有关的变量,随z变化
                            pop_s[im][(3 + J + i) * I + t]=[sum(D[j, 0] * pop_s[im][(j+3) * I + i] * s[j, i] * n[i, t] for j in range(J))]
                    else:
                        pop_s[im][i]=0  # 否则,变异为0,那么对应的P,V,z,u都取0
                        pop_s[im][I + i] =0
                        pop_s[im][2 * I + i] =0
                        for g in range(0, J):
                            pop_s[im][(g + 3) * I + i]=0
                        for t in range(I):
                            pop_s[im][(3 + J + i) * I + t]=0
                elif i <=2*I-1:  # 如果变异基因为P
                    if pop_s[im][i]==0:  # 规定是P不为0是才进行变异,若P=0
                        pop_s[im][i] =0  # 该值仍取0
                    else:  # 若P不为0
                        pop_s[im][i] = random.randint(2, 100) # 变异值为范围内随机一个值
                        pop_s[im][I+i]=random.randint(1,math.ceil(pop_s[im][i]*alpha))  # 对应的V=P*alpha
                elif i <=3*I-1:  # 如果变异基因为V
                    if pop_s[im][i]==0:  # 规定是V不为0是才进行变异,若V=0
                        pop_s[im][i] =0  # 该仍取0
                    else:  # 若V不为0
                        pop_s[im][i] = random.randint(0, pop_s[im][i-I])
                elif i <=(3+I)*J-1:  # 如果变异基因为z
                    if pop_s[im][i]==0:  # 规定是z不为0是才进行变异,若z=0
                        pop_s[im][i] =0  # 该仍取0
                    else:  # 若z不为0
                        pop_s[im][i] = random.uniform(0, 1)  # 变异值在0,1内随机生成一个小数
                        k = divmod(i-3*I, I)[1]  #k=i-3*I/I的余数,将i值从(3*I-(3+J)*I-1)映射到(0,I-1)
                        for t in range(I):  #用k代替279行中的i,得到u关于z的关系式
                            pop_s[im][(3 + J +k) * I + t]=[sum(D[j, 0] * pop_s[im][(j+3)*I+k] * s[j, k] * n[k, t] for j in range(J))]
                else:
                    pop_s[im][i] = pop_s[im][i]  # u值不变异,根据z值得到
        j+=1
    return pop_s

pop = initial_pop(7)  # 初始种群,内有7个个体,列表
# print(pop)
# print(len(pop))
fit = get_fitness(pop, 7, 500000, 0.5)  # 得到每个个体的适应度,列表
fit2 = fit_sort(fit)  # 得到降序排列的适应度
pop_e = get_elite(pop, fit, fit2, 2)  # 选取2个精英个体直接进入子代
pop_s = selection(pop, fit, 6)  # 从初始种群中选择6个进行遗传操作
pop_c = crossover(pop_s, 0.7)  # 得到交叉后的个体,列表,内含6个个体
print(pop_c)
# print(len(pop_c))
pop_m=mutate(pop_c,0.2)
print(pop_m)
print(len(pop_m))

# print(len(pop_m))

输出pop_c,pop_m,为列表嵌套列表,外列表内有6个元素len(pop_c),len(pop_m)=6,每个元素代表一个个体,内列表有I+I+I+JI+II(858)个元素,I=13,J=50,每个元素代表一个基因。

发布了13 篇原创文章 · 获赞 0 · 访问量 107

猜你喜欢

转载自blog.csdn.net/huahua20190514/article/details/103625216