ZDT3 - NSGA2 by pxc

master
xtu202105570214 2 years ago
parent 99d50d692f
commit dca307b79b

@ -0,0 +1,278 @@
import math
import random
import matplotlib.pyplot as plt
import copy
# 用的是ZDT3测试函数
# First function to optimize
def function1(x):
return x[0]
# Second function to optimize
def function2(x):
gx = funcationG(x)
value = 1 - math.sqrt(x[0] / gx) - x[0] / gx * math.sin(10 * math.pi * x[0])
return gx * value
def funcationG(x):
sumX = 0
for i in range(1, varNum):
sumX = sumX + x[i]
return 1 + (9 * sumX) / (varNum - 1)
# Function to find index of list
def index_of(a, list):
for i in range(0, len(list)):
if list[i] == a:
return i
return -1
# Function to sort by values
def sort_by_values(list1, values):
sorted_list = []
while (len(sorted_list) != len(list1)):
if index_of(min(values), values) in list1:
sorted_list.append(index_of(min(values), values))
values[index_of(min(values), values)] = math.inf
return sorted_list
# Function to carry out NSGA-II's fast non dominated sort
def fast_non_dominated_sort(values1, values2):
S = [[] for i in range(0, len(values1))] # 解所支配的集合
front = [[]] # 排序结果
n = [0 for i in range(0, len(values1))] # 支配者数量
rank = [0 for i in range(0, len(values1))]
for p in range(0, len(values1)):
S[p] = []
n[p] = 0
for q in range(0, len(values1)):
if (values1[p] < values1[q] and values2[p] < values2[q]) or (
values1[p] <= values1[q] and values2[p] < values2[q]) or (
values1[p] < values1[q] and values2[p] <= values2[q]):
if q not in S[p]:
S[p].append(q)
elif (values1[q] < values1[p] and values2[q] < values2[p]) or (
values1[q] <= values1[p] and values2[q] < values2[p]) or (
values1[q] < values1[p] and values2[q] <= values2[p]):
n[p] = n[p] + 1
if n[p] == 0:
rank[p] = 0
if p not in front[0]:
front[0].append(p)
i = 0
while (front[i] != []):
Q = []
for p in front[i]:
for q in S[p]:
n[q] = n[q] - 1
if (n[q] == 0):
rank[q] = i + 1
if q not in Q:
Q.append(q)
i = i + 1
front.append(Q)
del front[len(front) - 1]
return front
# Function to calculate crowding distance 拥挤度距离计算
def crowding_distance(values1, values2, front):
distance = [0 for i in range(0, len(front))]
sorted1 = sort_by_values(front, values1[:])
sorted2 = sort_by_values(front, values2[:])
distance[0] = math.inf
distance[len(front) - 1] = math.inf
for k in range(1, len(front) - 1):
distance[k] = distance[k] + (values1[sorted1[k + 1]] - values1[sorted1[k - 1]]) / (max(values1) - min(values1))
for k in range(1, len(front) - 1):
distance[k] = distance[k] + (values2[sorted2[k + 1]] - values2[sorted2[k - 1]]) / (max(values2) - min(values2))
return distance
# 二进制交叉
def crossover(individuala, individualb, a, b):
individual1 = copy.deepcopy(individuala)
individual2 = copy.deepcopy(individualb)
for j in range(min(a, b), max(a, b) + 1):
u = random.random()
if u < 0.5:
r = (2 * u) ** (1 / (NC + 1))
else:
r = (1 / (2 * (1 - u))) ** (1 / (NC + 1))
individual1[j] = 0.5 * ((1 + r) * individual1[j] + (1 - r) * individual2[j])
individual2[j] = 0.5 * ((1 - r) * individual1[j] + (1 + r) * individual2[j])
individual1[j] = 1 if individual1[j] > 1 else individual1[j] # 此处需要修改为常量
individual2[j] = 1 if individual2[j] > 1 else individual2[j]
individual1[j] = 0 if individual1[j] < 0 else individual1[j]
individual2[j] = 0 if individual2[j] < 0 else individual2[j]
return individual1, individual2
# 多项式变异
def mutation(individual, a):
individualTemp = copy.deepcopy(individual)
u = random.random()
if u < 0.5:
r = (2 * u) ** (1 / (NM + 1)) - 1
else:
r = (1 - (2 * (1 - u))) ** (1 / (NM + 1))
individualTemp[a] = individualTemp[a] + r
individualTemp[a] = 1 if individualTemp[a] > 1 else individualTemp[a] # 此处需要修改为常量
individualTemp[a] = 0 if individualTemp[a] < 0 else individualTemp[a]
return individualTemp
# 使用此函数之前要确保非支配排序解中都按照拥挤度排序过了
def competition(non_dominated_sorted, numOfSelect):
selectionResult = []
non_dominated_sortedTemp = []
for i in range(0, len(non_dominated_sorted)):
for j in range(0, len(non_dominated_sorted[i])):
non_dominated_sortedTemp.append(non_dominated_sorted[i][j])
while len(selectionResult) < numOfSelect:
selections = [random.randint(0, popSize - 1) for i in range(0, popSize // 2)]
selectionResult.append(non_dominated_sortedTemp[min(selections)])
return selectionResult
min_x = 0
max_x = 1 # x1 属于[0,1]
varNum = 30 # xi 中i的最大个数
popSize = 100 # 种群个数
max_gen = 500 # 最大迭代次数
pc = 0.9 # 交叉
pm = 0.01 # 变异
NC = 20
NM = 20
# 初始化种群
solution = []
for i in range(0, popSize):
solution.append([random.random() for j in range(0, varNum)])
times = 0
non_dominated_sorted_solution = []
function1_values = []
function2_values = []
while times < max_gen:
# 计算种群中,每个个体的两个目标函数值
function1_values = [function1(solution[i]) for i in range(0, popSize)]
function2_values = [function2(solution[i]) for i in range(0, popSize)]
# 快速非支配排序
non_dominated_sorted_solution = fast_non_dominated_sort(function1_values[:], function2_values[:])
# 计算拥挤度
crowding_distance_values = []
for i in range(0, len(non_dominated_sorted_solution)):
crowding_distance_values.append(
crowding_distance(function1_values[:], function2_values[:], non_dominated_sorted_solution[i][:]))
# 按照拥挤度排序
for i in range(0, len(non_dominated_sorted_solution)):
non_dominated_sorted_solution2_1 = [
index_of(non_dominated_sorted_solution[i][j], non_dominated_sorted_solution[i]) for j in
range(0, len(non_dominated_sorted_solution[i]))]
front22 = sort_by_values(non_dominated_sorted_solution2_1[:], crowding_distance_values[i][:]) # 按照拥挤度排序
non_dominated_sorted_solution[i] = [non_dominated_sorted_solution[i][front22[j]] for j in
range(0, len(non_dominated_sorted_solution[i]))]
non_dominated_sorted_solution[i].reverse() # 翻转之后是从大到小排序,拥挤度
solution2 = copy.deepcopy(solution)
# 竞标赛选取
offSpring = competition(non_dominated_sorted_solution, popSize)
# 交叉
for i in range(0, len(offSpring) // 2):
rc = random.random()
if (rc < pc):
index1 = random.randint(0, varNum - 1)
index2 = random.randint(0, varNum - 1)
while index1 == index2:
index1 = random.randint(0, varNum - 1)
indi1, indi2 = crossover(solution[offSpring[i]], solution[offSpring[len(offSpring) - i - 1]], index1,
index2)
solution2.append(indi1)
solution2.append(indi2)
# 变异
for i in range(0, len(offSpring)):
rm = random.random()
if rm < pm:
indexOfM = random.randint(0, varNum - 1)
muIndi = mutation(solution[offSpring[i]], indexOfM)
solution2.append(muIndi)
# 计算函数值
lengthOfSolution2 = len(solution2)
function1_values2 = [function1(solution2[i]) for i in range(0, lengthOfSolution2)]
function2_values2 = [function2(solution2[i]) for i in range(0, lengthOfSolution2)]
# 非支配快速排序
non_dominated_sorted_solution2 = fast_non_dominated_sort(function1_values2[:], function2_values2[:])
# 计算拥挤度
crowding_distance_values2 = []
for i in range(0, len(non_dominated_sorted_solution2)):
crowding_distance_values2.append(
crowding_distance(function1_values2[:], function2_values2[:], non_dominated_sorted_solution2[i][:]))
# 产生新的种群
new_solution = []
for i in range(0, len(non_dominated_sorted_solution2)):
non_dominated_sorted_solution2_1 = [
index_of(non_dominated_sorted_solution2[i][j], non_dominated_sorted_solution2[i]) for j in
range(0, len(non_dominated_sorted_solution2[i]))]
front22 = sort_by_values(non_dominated_sorted_solution2_1[:], crowding_distance_values2[i][:]) # 按照拥挤度排序
front = [non_dominated_sorted_solution2[i][front22[j]] for j in
range(0, len(non_dominated_sorted_solution2[i]))]
front.reverse() # 翻转之后是从大到小排序,拥挤度
for value in front:
new_solution.append(value)
if (len(new_solution) == popSize):
break
if (len(new_solution) == popSize):
break
solution = [solution2[i] for i in new_solution]
times = times + 1
print('This is ', times, '\n')
# Lets plot the final front now
minF1 = []
minF2 = []
for k in non_dominated_sorted_solution[0]:
minF1.append(function1_values[k])
minF2.append(function2_values[k])
# 打印第一层
print("The best front for Generation number ", times, " is")
for valuez in non_dominated_sorted_solution[0]:
print(solution[valuez:], end=" ")
print("\n")
plt.xlabel('F 1', fontsize=15)
plt.ylabel('F 2', fontsize=15)
plt.scatter(minF1, minF2)
plt.show()
Loading…
Cancel
Save