定义优化问题
minx f(x)s.t. gi(x)≤0,i=1,⋯ ,I, hj(x)=0,j=1,⋯ ,J, x∈Ω.\begin{align*} \min_{\boldsymbol x} &~~ f(\boldsymbol x)\\ {\rm s.t.} &~~ g_i (\boldsymbol x) \le 0, i = 1, \cdots,I, \\ &~~ h_j (\boldsymbol x) = 0, j = 1, \cdots,J, \\ &~~ \boldsymbol x \in \Omega. \end{align*}xmins.t. f(x) gi(x)≤0,i=1,⋯,I, hj(x)=0,j=1,⋯,J, x∈Ω.
启发式算法一般只要求:给定一个 x\boldsymbol xx,能够计算它好不好,不一定需要梯度。
通用数学框架
假设第 ttt 代有 MMM 个候选解:
X(t)={x1(t),⋯ ,xM(t)} \mathcal X^{(t)} = \left\{ \boldsymbol x_1^{(t)}, \cdots, \boldsymbol x_M^{(t)} \right\} X(t)={x1(t),⋯,xM(t)}
1.生成新解
对每个候选解,根据某种搜索规则生成新解:
zi(t)=G(xi(t),xbest(t),θ(t),ξi(t)) \boldsymbol z_i^{(t)} = \mathcal G \left( \boldsymbol x_i^{(t)}, \boldsymbol x_{\rm best}^{(t)}, \boldsymbol{\theta}^{(t)}, \boldsymbol{\xi}_i^{(t)} \right) zi(t)=G(xi(t),xbest(t),θ(t),ξi(t))
其中:
- G\mathcal GG:新解生成规则
- xbest\boldsymbol x_{\rm best}xbest:当前最好解
- θ\boldsymbol \thetaθ:算法参数
- ξ\boldsymbol{\xi}ξ:随机数
不同算法的核心区别就是 G\mathcal GG 不同。
2.边界或约束修复
如果新解越界:
zi(t)∉Ω \boldsymbol z_i^{(t)} \notin \Omega zi(t)∈/Ω
则进行修复或投影:
z^i(t)=R(zi(t)) \hat{\boldsymbol z}_i^{(t)} = \mathcal R (\boldsymbol z_i^{(t)}) z^i(t)=R(zi(t))
3.评价新解
计算适应度:F(z^i(t))F(\hat{\boldsymbol z}_i^{(t)})F(z^i(t))
有约束时,可以采用罚函数:
- 最小化:F(x)=f(x)+∑xμcVc(x)F(\boldsymbol x) = f(\boldsymbol x) + \sum_x \mu_c V_c(\boldsymbol x)F(x)=f(x)+∑xμcVc(x)
- 最大化:F(x)=f(x)−∑xμcVc(x)F(\boldsymbol x) = f(\boldsymbol x) - \sum_x \mu_c V_c(\boldsymbol x)F(x)=f(x)−∑xμcVc(x)
4.选择下一代
比较旧解和新解:X(t+1)=S(X(t),Z^(t))\mathcal X^{(t + 1)} = \mathcal S \left( \mathcal X^{(t)}, \hat{\mathcal Z}^{(t)} \right)X(t+1)=S(X(t),Z^(t)),其中 S\mathcal SS是选择或替换规则。
最后更新历史最好解:
xbest(t+1)=argminx∈X(t+1)F(x) \mathcal x_{\rm best}^{(t + 1)} = {\rm arg min}_{\boldsymbol x \in \mathcal X^{(t + 1)}} F(\boldsymbol x) xbest(t+1)=argminx∈X(t+1)F(x)
通用伪代码
输入:目标函数、约束、变量范围、种群规模 M、最大迭代次数 T
1. 初始化候选解 x_1, ..., x_M
2. 修复越界或不可行解
3. 计算所有候选解的适应度
4. 记录当前最好解 x_best
5. for t = 1, ..., T
更新算法参数
for i = 1, ..., M
根据搜索规则生成新解 z_i
对 z_i 进行边界处理或约束修复
计算 z_i 的目标函数与违反量
比较 z_i 和原来的 x_i
决定接受还是拒绝 z_i
end
更新全局最好解 x_best
如果满足终止条件
break
end
end
6. 输出最好的可行解 x_best
核心模块
1.解的表示
首先要回答:一个候选解究竟是什么?
例如:
- 调度问题:一个排列;
- 路径规划:一串节点;
- 波束赋形:一个复矩阵;
- 天线选择:一个0--1向量。
2.初始化
生成第一批解:
xi(0)∼某种分布 \boldsymbol x_i^{(0)} \sim\text{某种分布} xi(0)∼某种分布
重点是:
- 是否覆盖整个搜索空间;
- 初始解是否可行;
- 不同算法是否使用相同初始种群;
- 是否用闭式解进行热启动。
3.适应度评价
适应度决定哪个解更好:
F(x) F(\mathbf x) F(x)
它可能等于原目标,也可能是加入罚项后的目标:
F(x)=f(x)−penalty F(\mathbf x) = f(\mathbf x)-\text{penalty} F(x)=f(x)−penalty
如果适应度设计错误,后面的搜索策略再复杂也没有意义。
4.新解生成
这是不同算法最核心的差异。
| 算法 | 生成新解的主要方式 |
|---|---|
| PSO | 向个体最优和全局最优移动 |
| GA | 选择、交叉、变异 |
| DE | 利用多个个体之间的差向量 |
| BA | 速度、频率、局部扰动 |
| GWO | 向多个领先个体靠近 |
| 模拟退火 | 在当前解的邻域内随机扰动 |
5.约束处理
常见方式包括:
- 罚函数;
- 投影;
- 截断;
- 可行性修复;
- 可行解优先规则;
- 增广拉格朗日;
- 特殊编码,直接保证可行。
对于简单约束,优先投影或修复;罚函数更通用,但不能严格保证可行。
6.选择与记忆
需要回答:
- 新解一定替换旧解吗?
- 只有更好的新解才替换吗?
- 是否保留历史最优?
- 是否保留若干精英个体?
- 不可行解能否进入下一代?
PSO使用个体历史最优和全局最优;GA通常使用选择和精英保留;DE通常采用一对一贪婪替换。
7.探索与开发
算法必须平衡:
探索:寻找新的区域 \text{探索:寻找新的区域} 探索:寻找新的区域
和
开发:在当前好解附近细化. \text{开发:在当前好解附近细化}. 开发:在当前好解附近细化.
常见策略是:
- 前期大步长、高随机性;
- 后期小步长、向最好解集中。
惯性递减、变异、随机重启、Lévy flight,本质上都在调节这两个过程。
8.终止与输出
常见终止条件:
t≥Tmax t\ge T_{\max} t≥Tmax
或者
∣Fbest(t)−Fbest(t−1)∣∣Fbest(t−1)∣≤ϵ \frac{|F_{\mathrm{best}}^{(t)}-F_{\mathrm{best}}^{(t-1)}|} {|F_{\mathrm{best}}^{(t-1)}|} \le\epsilon ∣Fbest(t−1)∣∣Fbest(t)−Fbest(t−1)∣≤ϵ
最终应输出最好可行解,而不仅仅是罚函数值最大的解。
小结
一种启发式算法可以概括为六个词:
编码、初始化、评价、更新、筛选、终止。
其中最重要的三个部分:
如何表示解+如何产生新解+如何处理约束。