Zhang X, Tian Y, Cheng R, et al. An efficient approach to nondominated sorting for evolutionary multiobjective optimization[J]. IEEE Transactions on Evolutionary Computation, 2014, 19(2): 201-213.
import numpy as np
import functools
import time
# O(n) 当n等于一千万(10000000)时大概 1s
Pop_Size = 1000 # 种群大小
N = 10 # 决策空间大小
M = 10 # 目标数
class Individual(object):
def __init__(self, gene, func):
self.gene = gene
self.func = func
pass
def __str__(self):
return '[gene=%s\n func=%s]\n' % (self.gene, self.func)
__repr__ = __str__
pass
def cmp(pop1, pop2):
i = 0
while i < M:
if pop1.func[i] < pop2.func[i]:
return -1
elif pop1.func[i] > pop2.func[i]:
return 1
else:
i += 1
# return 0
pass
pass
return 0
def init_population():
population = []
for i in range(Pop_Size):
gene = [np.random.randint(0, 2) for j in range(N)]
func = [np.random.randint(0, Pop_Size/2) for j in range(M)]
pop = Individual(gene, func)
population.append(pop)
pass
return population
def jude_dominating(p, q):
# 最小化问题
i = 0
flag = True
cnt = 0
while i < M:
if p.func[i] > q.func[i]:
flag = False
break
pass
elif p.func[i] == q.func[i]:
cnt += 1
pass
i += 1
pass
if flag:
if cnt < M: # 不能所有目标相等
return True
else:
return False
pass
else: # 存在一个目标不小于则不支配
return False
pass
def fast_sort(population):
s = {}
n = {}
f = []
pt = [] # 记录一层非支配层
for p in population:
st = [] # p支配的个体
nt = 0 # 支配p的个体数
for q in population:
if jude_dominating(p, q):
st.append(q)
pass
elif jude_dominating(q, p):
nt += 1
pass
pass
# s[p.idx] = st # 第i个个体所支配的个体集合
s[id(p)] = st
# n[p.idx] = nt # 支配的第i个个体的个体数
n[id(p)] = nt
if nt == 0: # 没有个体支配p
pt.append(p)
pass
pass
f.append(pt)
i = 0
while len(f[i]) > 0: # 由于判断条件,会多一个空层
pt = []
for p in f[i]:
# for q in s[p.idx]: # q下一层支配,则-1
for q in s[id(p)]: # q下一层支配,则-1
n[id(q)] -= 1
# n[q.idx] -= 1
# if n[q.idx] == 0: # 不存在支配q的个体,则加入当前层
if n[id(q)] == 0: # 不存在支配q的个体,则加入当前层
pt.append(q)
pass
pass
pass
i += 1
f.append(pt)
pass
f.pop()
return f
def sequential_search_strategy(p, f):
x = len(f) # 已经被分配的支配层数
k = 0 # 当前检索的层
while True:
flag = False
for q in reversed(f[k]):
if jude_dominating(q, p):
flag = True
break
pass
pass
if flag: # p 被f[k]中的个体支配
k += 1
if k >= x:
t = []
f.append(t)
# return x + 1
x += 1
f[k].append(p)
break
pass
pass
else: # p 不被f[k]中的个体支配
# return k
f[k].append(p)
break
pass
pass
pass
# 二分思想
def binary_search_strategy(p, f):
x = len(f) # 已经找到的支配层数
k_min = 0 # 检索的最底层
k_max = x # 检索的最高层
# k = int(np.floor((k_max+k_min)/2 + 1/2)) # 当前检索的层
k = int((k_max+k_min)/2)
while True:
flag = False
for q in reversed(f[k]):
if jude_dominating(q, p):
flag = True
break
pass
pass
if flag: # k小了,要往上层走,直到k==k_max-1
# k_min = k # k层能支配p 需要判断高层是否有支配p的。
if (k == k_max-1) and (k_max < x): # k是支配p的直接上一层
# return k_max
f[k_max].append(p)
break
pass
elif k == x-1: # 已存在的最后一层(k)支配p,则需要新加入一层
# return x+1
# x += 1
t = []
f.append(t)
f[x].append(p)
x += 1
break
pass
else: # k层能支配p 但不是直接支配p的一层 需要判断高层是否有支配p的。
# k = np.floor((k_max + k_min)/2 + 1/2)
k_min = k
k = int((k_max + k_min)/2)
pass
pass
else: # k大了,要往下层走,直到k==k_min+1
if k == k_min: # 当k==k_min 说明k是不能支配p的最小一层(就是说比k小的层通通支配p)
# return k
f[k].append(p)
break
pass
else: # k层不能支配p 但不是最小的层 需要往下层走。
k_max = k
k = int((k_max+k_min)/2)
pass
pass
pass
pass
def ens_ss(population):
f = [[]]
# population_sort = sorted(population, key=lambda individual: individual.f1)
# print(population)
population_sort = sorted(population, key=functools.cmp_to_key(cmp))
# print(population_sort)
for pop in population_sort:
sequential_search_strategy(pop, f)
# binary_search_strategy(pop, f)
pass
return f
def ens_bs(population):
f = [[]]
# population_sort = sorted(population, key=lambda individual: individual.f1)
# print(population)
population_sort = sorted(population, key=functools.cmp_to_key(cmp))
# print(population_sort)
for pop in population_sort:
# sequential_search_strategy(pop, f)
binary_search_strategy(pop, f)
pass
return f
pp = init_population()
print('********************fast_sort********************')
t1 = time.time()
ff = fast_sort(pp)
print(time.time()-t1)
# for tt in ff:
# print('front size=', len(tt))
# print(tt)
# pass
print('********************binary_search********************')
t1 = time.time()
ff = ens_bs(pp)
print(time.time()-t1)
# for tt in ff:
# print('front size=', len(tt))
# print(tt)
# pass
print('********************sequential_search********************')
t1 = time.time()
ff = ens_ss(pp)
print(time.time()-t1)
# for tt in ff:
# print('front size=', len(tt))
# print(tt)
# pass
当种群大小population_size=1000,目标数M=10时,binary_search 和 sequential_search 都是该论文提出的非支配排序方法,从运行结果能看出,该论文提出的排序方法优于传统的快速非支配排序算法(fast_sort[1])。
[1] Deb K, Pratap A, Agarwal S, et al. A fast and elitist multiobjective genetic algorithm: NSGA-II[J]. IEEE transactions on evolutionary computation, 2002, 6(2): 182-197.
[4] Yang X, Zou J, Yang S, et al. A Fuzzy Decision Variables Framework for Large-scale Multiobjective Optimization[J]. IEEE Transactions on Evolutionary Computation, 2021.
[5] Zou J, Yang X, Liu Z, et al. Multiobjective Bilevel Optimization Algorithm Based on Preference Selection to Solve Energy Hub System Planning Problems[J]. Energy, 2021: 120995.
[6] Liu J, Yang X, Liu Z, et al. Investigation and evaluation of building energy flexibility with energy storage system in hot summer and cold winter zones[J]. Journal of Energy Storage, 2022, 46: 103877.