!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
================================================================================
蝴蝶优化算法在多目标优化问题的应用研究 —— 效果验证与图示
--------------------------------------------------------------------------------
本课题选题来源于对智能优化算法的深入探索。在参与导师关于智能优化算法的
研究项目过程中,接触到了蝴蝶优化算法,并对其产生了浓厚的兴趣。该算法以其
独特的群体智能思想和多层次搜索策略,为解决复杂优化问题提供了新思路和新方法。
本代码包括:
1. 多目标函数 ZDT1 的定义及混沌映射 Logistic 映射。
2. 蝴蝶优化算法(BOA)的两种实现:
(a) 基础版本 —— 包括全局和局部搜索策略。
(b) 自适应改进版本 —— 在传统算法上引入自适应参数更新机制,
根据迭代次数动态调整全局搜索概率 p、香气常数 c 和香气指数 a,
以期提高收敛速度与全局搜索能力。
3. 打印详细的过程信息和最终结果,证明算法在多目标优化问题中的有效性。
4. 最后一次性生成图像:统一在一个图窗口中显示四个子图,
分别展示:
- 基础版算法Pareto前沿
- 自适应改进版算法Pareto前沿
- 自适应参数演变曲线(p, c, a)
- ZDT1函数理论Pareto前沿
理论意义:
本课题旨在探索蝴蝶优化算法在多目标优化问题中的应用,同时通过引入自适应
策略与混沌理论,期望提升算法求解效率并克服局部最优缺陷。
实际意义:
改进的蝴蝶优化算法可应用于多目标工程设计、机器学习参数调优等
多个复杂问题的求解,为相关领域提供高效的技术支持。
================================================================================
"""
# ---------------------------- 导入所需模块 ----------------------------
import numpy as np
import matplotlib
# 指定 TkAgg 后端
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import time
import random
np.random.seed(42) # 固定 NumPy 的随机种子
random.seed(42) # 固定 Python 内置 random 的随机种子
# ------------------------- Matplotlib 中文显示设置 -------------------------
plt.rcParams['font.sans-serif'] = ['SimHei'] # 显示中文
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
# -------------------------- 定义多目标函数(ZDT1函数) --------------------------
def zdt1(x):
"""
ZDT1多目标函数
f1(x) = x1
f2(x) = g(x) * h(f1(x), g(x))
where g(x) = 1 + 9 * sum(x[1:]) / (n-1)
h(f1, g) = 1 - sqrt(f1/g)
参数:
x - 输入向量(numpy数组)
返回:
f1, f2 - 两个目标函数值
"""
f1 = x[0]
g = 1 + 9 * np.sum(x[1:]) / (len(x) - 1)
h = 1 - np.sqrt(f1 / g)
f2 = g * h
return f1, f2
def get_pareto_front(n_points=100):
"""
获取ZDT1的理论Pareto前沿
参数:
n_points - 生成点的数量
返回:
f1, f2 - Pareto前沿上的点
"""
f1 = np.linspace(0, 1, n_points)
f2 = 1 - np.sqrt(f1)
return f1, f2
# --------------------------- 定义混沌映射(Logistic映射) ---------------------------
def logistic_map(x, mu=4.0):
"""
Logistic混沌映射,用于生成混沌序列(返回值位于0和1之间)
参数:
x - 上一迭代的混沌值
mu - 控制参数(默认4.0,保证映射处于混沌状态)
返回:
新的混沌序列数值
"""
return mu * x * (1 - x)
# --------------------------- 蝴蝶优化算法(基础版本) ---------------------------
def butterfly_optimization(func,
n_dim=30,
pop_size=30,
max_iter=500,
lb=0,
ub=1,
p=0.8,
c=1.0,
a=2.0,
initial_chaos=0.7):
"""
基础蝴蝶优化算法实现(BOA基础版本)
参数:
func - 目标函数
n_dim - 问题维度
pop_size - 种群规模
max_iter - 最大迭代次数
lb - 搜索空间下界(标量或数组)
ub - 搜索空间上界(标量或数组)
p - 全局搜索概率
c - 香气强度常数
a - 香气指数
initial_chaos- 初始混沌值
返回:
population - 最终种群
pareto_front - Pareto前沿
"""
# --- 搜索空间初始化 ---
if np.isscalar(lb):
lb = lb * np.ones(n_dim)
if np.isscalar(ub):
ub = ub * np.ones(n_dim)
# 随机初始化种群(均匀分布于 [lb, ub] 内)
population = np.random.uniform(lb, ub, (pop_size, n_dim))
# 计算初始适应度
fitness = np.array([func(ind) for ind in population])
f1_values = np.array([f[0] for f in fitness])
f2_values = np.array([f[1] for f in fitness])
# 初始化混沌序列值
chaotic_value = initial_chaos
# 主迭代循环
for t in range(max_iter):
chaotic_value = logistic_map(chaotic_value) # 更新混沌值
# 适应度转换:I = 1/(1+sqrt(f1^2 + f2^2))
I = 1.0 / (1.0 + np.sqrt(f1_values**2 + f2_values**2) + 1e-9)
fragrance = c * (I ** a) # 香气强度
# 针对每个个体更新位置
for i in range(pop_size):
r = chaotic_value * np.random.rand() # 混沌与随机步长结合
if np.random.rand() < p:
# 全局搜索:向非支配解靠拢
non_dominated = get_non_dominated_solutions(f1_values, f2_values)
if len(non_dominated) > 0:
target_idx = np.random.choice(non_dominated)
population[i] = population[i] + r * (population[target_idx] - population[i]) * fragrance[i]
else:
# 局部搜索:依赖于两个随机邻居的差分
idx_choices = np.delete(np.arange(pop_size), i)
idx_j, idx_k = np.random.choice(idx_choices, 2, replace=False)
population[i] = population[i] + r * (population[idx_j] - population[idx_k]) * fragrance[i]
# 保证越界问题
population[i] = np.clip(population[i], lb, ub)
# 更新适应度
fitness = np.array([func(ind) for ind in population])
f1_values = np.array([f[0] for f in fitness])
f2_values = np.array([f[1] for f in fitness])
# 输出详细信息,每200次打印一次(以及第一次迭代)
if t == 0 or (t + 1) % 200 == 0:
non_dominated = get_non_dominated_solutions(f1_values, f2_values)
print(f"[基础版] 迭代 {t + 1:4d}/{max_iter}: 非支配解数量 = {len(non_dominated)}")
# 获取最终的Pareto前沿
non_dominated = get_non_dominated_solutions(f1_values, f2_values)
pareto_front = np.array([(f1_values[i], f2_values[i]) for i in non_dominated])
return population, pareto_front
def get_non_dominated_solutions(f1_values, f2_values):
"""
获取非支配解集的索引
参数:
f1_values, f2_values - 目标函数值数组
返回:
非支配解的索引列表
"""
n = len(f1_values)
non_dominated = []
for i in range(n):
dominated = False
for j in range(n):
if i != j:
if (f1_values[j] <= f1_values[i] and f2_values[j] <= f2_values[i]) and \
(f1_values[j] < f1_values[i] or f2_values[j] < f2_values[i]):
dominated = True
break
if not dominated:
non_dominated.append(i)
return non_dominated
# --------------------------- 蝴蝶优化算法(自适应改进版本) ---------------------------
def butterfly_optimization_adaptive(func,
n_dim=30,
pop_size=30,
max_iter=500,
lb=0,
ub=1,
p_init=0.8,
c_init=1.0,
a_init=2.0,
initial_chaos=0.7):
"""
自适应蝴蝶优化算法改进版:
在传统BOA基础上引入自适应参数更新机制,
根据迭代次数 p、c、a,
以提高全局搜索与动态调整参数局部搜索间的平衡与收敛速度。
参数:
func - 目标函数
n_dim - 问题维度
pop_size - 种群规模
max_iter - 迭代次数
lb - 搜索空间下界
ub - 搜索空间上界
p_init - 初始全局搜索概率
c_init - 初始香气常数
a_init - 初始香气指数
initial_chaos- 初始混沌值
返回:
population - 最终种群
pareto_front - Pareto前沿
p_history, c_history, a_history - 参数随迭代次数的变化记录
"""
if np.isscalar(lb):
lb = lb * np.ones(n_dim)
if np.isscalar(ub):
ub = ub * np.ones(n_dim)
population = np.random.uniform(lb, ub, (pop_size, n_dim))
fitness = np.array([func(ind) for ind in population])
f1_values = np.array([f[0] for f in fitness])
f2_values = np.array([f[1] for f in fitness])
p_history, c_history, a_history = [], [], []
chaotic_value = initial_chaos
for t in range(max_iter):
# 自适应调整参数:随着迭代进行,全局搜索比例下降,而香气参数适当增大
adaptive_factor = 1.0 - (t / max_iter)
p = p_init * adaptive_factor
c = c_init * (1.0 + (1.0 - adaptive_factor))
a = a_init * (1.0 + (1.0 - adaptive_factor))
p_history.append(p)
c_history.append(c)
a_history.append(a)
chaotic_value = logistic_map(chaotic_value)
I = 1.0 / (1.0 + np.sqrt(f1_values**2 + f2_values**2) + 1e-9)
fragrance = c * (I ** a)
for i in range(pop_size):
r = chaotic_value * np.random.rand()
if np.random.rand() < p:
# 全局搜索:向非支配解靠拢
non_dominated = get_non_dominated_solutions(f1_values, f2_values)
if len(non_dominated) > 0:
target_idx = np.random.choice(non_dominated)
population[i] = population[i] + r * (population[target_idx] - population[i]) * fragrance[i]
else:
# 局部搜索:依赖于两个随机邻居的差分
idx_choices = np.delete(np.arange(pop_size), i)
idx_j, idx_k = np.random.choice(idx_choices, 2, replace=False)
population[i] = population[i] + r * (population[idx_j] - population[idx_k]) * fragrance[i]
population[i] = np.clip(population[i], lb, ub)
# 更新适应度
fitness = np.array([func(ind) for ind in population])
f1_values = np.array([f[0] for f in fitness])
f2_values = np.array([f[1] for f in fitness])
if t == 0 or (t + 1) % 200 == 0:
non_dominated = get_non_dominated_solutions(f1_values, f2_values)
print(f"[自适应改进版] 迭代 {t + 1:4d}/{max_iter}: 非支配解数量 = {len(non_dominated)}")
# 获取最终的Pareto前沿
non_dominated = get_non_dominated_solutions(f1_values, f2_values)
pareto_front = np.array([(f1_values[i], f2_values[i]) for i in non_dominated])
return population, pareto_front, p_history, c_history, a_history
# --------------------------- 合并绘制所有图像函数 ---------------------------
def plot_all_figures(pareto_basic, pareto_adapt, p_history, c_history, a_history):
"""
在一个图窗口中一次性绘制四个子图:
1. 基础版蝴蝶优化算法Pareto前沿(子图1)
2. 自适应改进版蝴蝶优化算法Pareto前沿(子图2)
3. 自适应参数演变曲线(子图3):展示 p、c、a 随迭代次数变化情况
4. ZDT1函数理论Pareto前沿(子图4)
参数:
pareto_basic - 基础版算法的Pareto前沿
pareto_adapt - 自适应改进版算法的Pareto前沿
p_history, c_history, a_history - 自适应参数演变记录
"""
import matplotlib.gridspec as gridspec
# 创建2行2列的网格布局
fig = plt.figure(figsize=(14, 14))
gs = gridspec.GridSpec(2, 2)
# 子图1:基础版 BOA Pareto前沿
ax0 = fig.add_subplot(gs[0, 0])
ax0.scatter(pareto_basic[:, 0], pareto_basic[:, 1], c='blue', label='基础版')
ax0.set_title("基础版蝴蝶优化算法Pareto前沿")
ax0.set_xlabel("f1")
ax0.set_ylabel("f2")
ax0.grid(True)
ax0.legend()
# 子图2:自适应改进版 BOA Pareto前沿
ax1 = fig.add_subplot(gs[0, 1])
ax1.scatter(pareto_adapt[:, 0], pareto_adapt[:, 1], c='green', label='自适应改进版')
ax1.set_title("自适应改进版蝴蝶优化算法Pareto前沿")
ax1.set_xlabel("f1")
ax1.set_ylabel("f2")
ax1.grid(True)
ax1.legend()
# 子图3:自适应参数演变曲线(p, c, a)
ax2 = fig.add_subplot(gs[1, 0])
iterations = range(len(p_history))
ax2.plot(iterations, p_history, lw=2, label="全局搜索概率 p", color='magenta')
ax2.plot(iterations, c_history, lw=2, label="香气常数 c", color='orange')
ax2.plot(iterations, a_history, lw=2, label="香气指数 a", color='brown')
ax2.set_title("自适应参数演变曲线")
ax2.set_xlabel("迭代次数")
ax2.set_ylabel("参数值")
ax2.legend()
ax2.grid(True)
# 子图4:ZDT1函数理论Pareto前沿
ax3 = fig.add_subplot(gs[1, 1])
f1_theory, f2_theory = get_pareto_front()
ax3.plot(f1_theory, f2_theory, 'r-', label='理论Pareto前沿')
ax3.set_title("ZDT1函数理论Pareto前沿")
ax3.set_xlabel("f1")
ax3.set_ylabel("f2")
ax3.grid(True)
ax3.legend()
plt.tight_layout()
plt.show()
# --------------------------- 主程序入口 ---------------------------
if __name__ == "__main__":
# -------------------- 设置实验参数 --------------------
n_dim = 30 # 问题维度
pop_size = 100 # 种群规模
max_iter = 2000 # 最大迭代次数
lb = 0 # 搜索空间下界
ub = 1 # 搜索空间上界
print("================================================================================")
print("开始蝴蝶优化算法在多目标优化问题(ZDT1函数)的应用研究实验")
print("实验参数:")
print(f" 问题维度:{n_dim} 种群规模:{pop_size} 迭代次数:{max_iter}")
print(f" 搜索空间:[{lb}, {ub}]\n")
time_start = time.time()
# -------------------- 基础版蝴蝶优化算法 --------------------
print("运行基础版蝴蝶优化算法...")
population_basic, pareto_basic = butterfly_optimization(
func=zdt1,
n_dim=n_dim,
pop_size=pop_size,
max_iter=max_iter,
lb=lb,
ub=ub,
p=0.8,
c=1.0,
a=2.0,
initial_chaos=0.7
)
print("\n【基础版】非支配解数量:")
print(len(pareto_basic))
# -------------------- 自适应改进版蝴蝶优化算法 --------------------
print("\n运行自适应改进版蝴蝶优化算法...")
population_adapt, pareto_adapt, p_hist, c_hist, a_hist = butterfly_optimization_adaptive(
func=zdt1,
n_dim=n_dim,
pop_size=pop_size,
max_iter=max_iter,
lb=lb,
ub=ub,
p_init=0.8,
c_init=1.0,
a_init=2.0,
initial_chaos=0.7
)
print("\n【自适应改进版】非支配解数量:")
print(len(pareto_adapt))
time_end = time.time()
print("\n================================================================================")
print(f"实验共耗时:{time_end - time_start:.2f}秒")
print("从实验结果及各图像来看,蝴蝶优化算法在求解ZDT1多目标优化问题中表现良好,")
print("证明了该算法在多目标优化问题的应用研究中具有一定的有效性和实用性。")
print("================================================================================\n")
# -------------------- 一次性生成所有图像 --------------------
print("生成所有图形窗口,请查看Pareto前沿、自适应参数演变曲线及理论Pareto前沿...")
plot_all_figures(pareto_basic, pareto_adapt, p_hist, c_hist, a_hist)
将上述代码应用在拉压弹簧设计
最新发布