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,每个元素代表一个基因。