
简介基于Matlab改进遗传算法求解带约束优化问题的源码包提供了一套完整实现面向需要解决工程优化问题的研究人员、学生和工程师尤其适合正在学习智能优化算法与约束处理的读者。资源共10个文件包括9个m脚本和1张jpg运行结果图压缩包整体仅29KB轻量便于快速下载与运行。核心m脚本划分清晰覆盖算法主流程、种群初始化、变异、交叉、锦标赛选择、目标函数计算、环境选择、运行记录与一键运行等关键环节模块化结构便于理解遗传算法各操作在约束场景中的实际写法另有运行结果图可直接查看求解效果。目前已有2121人学习/下载说明其具备较强的参考价值。借助这份源码读者不仅能掌握罚函数、约束修正等策略在遗传算法中的落地方式还能理解种群大小、交叉概率等参数对求解性能的影响进而将框架迁移至自身优化项目中。1. 基于改进遗传算法求解带约束优化问题到底卡在哪带约束优化在工程里出现频率远远高于无约束优化结构尺寸要满足应力上限生产计划要咬住产能下限路径规划得避开禁飞区。MATLAB 自带的fmincon对凸问题好用但对非凸、离散、不可导的目标函数经常陷入局部最优或者因为初始点选得不好直接发散。遗传算法GA的好处是不依赖梯度、能做全局搜索但直接把标准 GA 拿过来解约束问题时约束处理往往是短板——罚函数惩罚系数调大调小都难受调大了种群容易早熟调小了可行解容易被淘汰。所谓“改进”核心方向就是三件事约束处理策略、自适应遗传算子、精英保留机制。这篇文章把带约束优化问题的建模、改进 GA 的关键算子和 MATLAB 实现串起来讲清楚每一步为什么这么做、参数怎么设、跑出问题看哪里最后给一个可以直接替换目标函数使用的完整骨架。2. 带约束优化的问题建模与改进遗传算法的改进落点2.1 约束优化问题的数学形式与处理难点带约束优化问题Constrained Optimization Problem, COP的标准形式是min f(x) s.t. g_i(x) 0, i 1, 2, ..., m h_j(x) 0, j 1, 2, ..., n lb x ub其中x是决策变量向量f(x)是目标函数g_i(x)是不等式约束h_j(x)是等式约束。工程里绝大多数问题可以用这个形式表达比如弹簧设计问题里f(x)是弹簧质量g_i(x)包含剪应力上限、频率下限、挠度限制等再比如压力容器设计约束涉及壁厚应力、体积要求。处理约束的传统手段是外点罚函数法把约束信息并入目标函数F(x) f(x) sigma * [ sum(max(0, g_i(x))^p) sum(|h_j(x)|^p) ]sigma是惩罚因子p一般取 2。这个方法直观但实际跑起来有两个问题一是 sigma 太小个体越过约束边界后适应度依然很好种群大量集中在不可行域二是 sigma 太大可行域边界附近的目标函数值被放大种群会过早收敛到第一个碰到的可行点附近失去全局搜索能力。更高频的坑在等式约束h_j(x) 0——浮点计算下精确等于 0 几乎不可能如果不把等式约束放宽成|h_j(x)| epsilon罚函数几乎永远在生效算法会不停地排斥带最优解潜力的个体。2.1.1 约束违反度的定义将上述约束合并为总的约束违反度constraint violationV(x) sum(max(0, g_i(x))) sum(max(0, |h_j(x)| - epsilon))V(x) 0表示个体是可行解。这样做的好处是把多个约束统一成一个标量为后续的约束支配比较提供了基础——改进 GA 的其中一个关键就是用这个 V 值来参与个体优劣排序而不是简单地在目标函数后面加一个惩罚项。2.2 改进 GA 比标准 GA 强在哪些算子标准 GA 的三个支柱是选择、交叉、变异。改进版不是推翻它们而是针对“约束环境下种群多样性容易崩塌”的问题做定向改动。常见做法如下。第一选择阶段采用锦标赛选择加可行性法则feasibility rule两个个体比较时先看可行性可行解优先于不可行解同为可行解时比较目标函数值同为不可行解时比较约束违反度。这个法则最早由 Deb 提出实践效果稳定代码实现也简单。第二交叉和变异不固定概率而是根据种群当前状态自适应调整。比如交叉概率pc随可行解比例变化pc pc_base - 0.2 * (feasible_ratio - 0.5)可行解多了就减小交叉率倾向局部精细搜索可行解少了就增大交叉率扩大探索范围。变异率同理当种群多样性下降比如个体间距离均值变小就适当提高变异概率。第三精英保留机制单独划出一块空间保存历史最优可行解不参与交叉变异每代结束时放回种群。这个保证算法不会因为变异破坏掉已经找到的最优可行个体。3. MATLAB 中改进 GA 的完整实现编码、排序、选择交叉变异3.1 从适应度函数到约束处理的代码骨架直接上代码。这里以 MATLAB 实现为例使用实数编码这是带约束连续优化问题的推荐做法——二进制串在解决高精度连续变量问题时字符串太长海明距离对相似实数不友好实数直接参与算术交叉即可保留收敛性。先定义目标函数和约束函数function f objfun(x) % 示例二元非线性目标函数 f 100 * (x(1)^2 - x(2))^2 (1 - x(1))^2; end function [g, h] confun(x) % 不等式约束: g 0 g(1) x(1)^2 x(2)^2 - 1.5; % 等式约束: h 0线性等式容易构造 h(1) x(1) x(2) - 0.5; end上面代码中的objfun是经典的 Rosenbrock 函数变形confun里包含了一个不等式和一个等式约束。约束写成g 0和h 0是 MATLAB 优化工具箱的通用约定格式我们自己的 GA 也沿用这个输入输出结构这样更换实际问题时只需要替换这两个函数。3.2 初始化、评估与约束违反度计算初始化用均匀随机数在变量边界内生成种群。注意边界lb和ub要作为函数参数传入不能写死在例子里。function pop init_pop(np, nv, lb, ub) % np: 种群大小, nv: 变量维数 pop lb (ub - lb) .* rand(np, nv); end function [fit_val, viol] eval_pop(pop, eps_eq) % 返回目标函数值列向量和总约束违反度列向量 np size(pop, 1); fit_val zeros(np, 1); viol zeros(np, 1); for i 1:np x pop(i, :); fit_val(i) objfun(x); [g, h] confun(x); % 等式约束放宽到 eps_eq 内视为满足 v sum(max(0, g)) sum(max(0, abs(h) - eps_eq)); viol(i) v; end endeps_eq一般取 1e-4 到 1e-6具体看约束的量纲。如果等式约束量级很大比如h 100*xy-501e-4 可能太紧要等比例放宽如果约束是线性等式也可以考虑用投影修复法把个体直接拉回流形面上但这是另一套分支本文不展开。3.3 锦标赛选择与可行性法则排序锦标赛选择的实现逻辑是每次从种群中随机抽tour_size个个体选出“最优秀”的一个进入交配池。这里“最优秀”的定义就是前面说的可行性法则function idx tournament(fit_val, viol, tour_size) np length(fit_val); % 随机抽取候选个体索引 candidates randperm(np, tour_size); best candidates(1); for k 2:tour_size cand candidates(k); % 可行解优先 if viol(cand) 1e-10 viol(best) 1e-10 best cand; elseif viol(cand) 1e-10 viol(best) 1e-10 % 保持原 best 不变 elseif viol(cand) 1e-10 viol(best) 1e-10 % 都不可行, 比违反度 if viol(cand) viol(best) best cand; end else % 都可行, 比目标函数值 if fit_val(cand) fit_val(best) best cand; end end end idx best; end比较逻辑要分层优先级从高到低依次是可行优于不可行都可行时目标函数小者优都不可行时约束违反度小者优。这个规则的一个关键点在于种群初期几乎没有可行解此时算法实际上是在最小化约束违反度也就是引导种群先“找到”可行域一旦找到哪怕一个可行解该可行解就会因为优先级高被反复选中、进入交配池周围会聚集大量后代从而保证可行域被充分开发。补充一点代码里对“可行”的判定用viol 1e-10但 eval 时等式约束已经用eps_eq放宽所以这个阈值选 1e-10 相当于保证不等式约束也是严格满足的。实际使用中可以把这个写成一个参数feas_tol。3.4 自适应交叉算子的参数与实现实数编码下最常用的交叉方式是模拟二进制交叉Simulated Binary Crossover, SBX和算术交叉。SBX 更贴近二进制交叉的分布特性但算术交叉代码更短实际收敛效果对多数工程问题足够。这里给出自适应算术交叉function [c1, c2] arithmetic_cross(p1, p2, pc, alpha) % pc: 交叉概率, alpha: 混合系数(0~1) if rand pc c1 alpha .* p1 (1 - alpha) .* p2; c2 alpha .* p2 (1 - alpha) .* p1; else c1 p1; c2 p2; end endalpha固定时后代落在两父本的连线上这是算术交叉的特点。工程实现里可以每代动态生成alpha rand后代分布范围更宽。对空间较大的问题更推荐 SBX它的分布因子eta_c控制后代与父本的接近程度eta_c 20是经验值值越大后代越集中在父本附近。自适应体现在调用层根据当前代可行解比例调整pc。feas_ratio sum(viol feas_tol) / np; pc 0.9 - 0.4 * feas_ratio; pm 0.1 0.3 * (1 - feas_ratio);这样设置的原因在于可行解比例高说明种群已经定位到可行域应当更多进行局部开发exploitation交叉率下调可行解比例低时突变增加避免全部个体被困在不可行区域反复横跳。3.5 变异操作与边界处理变异采用多项式变异Polynomial Mutation这是 NSGA-II 中配合 SBX 使用的经典变异算子能够在实数空间内保持一个可控的扰动分布function child poly_mutate(x, lb, ub, pm, eta_m) % pm: 变异概率, eta_m: 变异分布指数, 常用 20 child x; for j 1:length(x) if rand pm r rand; if r 0.5 delta (2*r)^(1/(eta_m1)) - 1; else delta 1 - (2*(1-r))^(1/(eta_m1)); end child(j) x(j) delta * (ub(j) - lb(j)); % 边界越界处理: 直接截断到最近边界 child(j) min(max(child(j), lb(j)), ub(j)); end end end边界截断比反射回边界内部要简单直接但代价是种群在边界处的密度会偏高如果需要降低边界聚集效应可以改成边界折返——超过上界就按2*upper - x反射回界内。多数工程问题约束的最优点并不在变量边界上截断处理足够可靠。4. 主循环整合、MATLAB 关键参数与典型调试经验4.1 完整的改进 GA 主循环将前面的模块组装成一个 main 函数function [best_x, best_f, history] ga_improved(lb, ub, opts) % opts 字段: np, maxgen, tour_size, eps_eq, feas_tol nv length(lb); np opts.np; pop init_pop(np, nv, lb, ub); [fit_val, viol] eval_pop(pop, opts.eps_eq); best_x []; best_f inf; history zeros(opts.maxgen, 2); % 每代最优目标值和可行比例 for gen 1:opts.maxgen feas_ratio sum(viol opts.feas_tol) / np; pc 0.9 - 0.4 * feas_ratio; pm 0.1 0.3 * (1 - feas_ratio); % 精英保存: 找当前代最优可行解 [min_viol, idx_v] min(viol); if min_viol opts.feas_tol fit_val(idx_v) best_f best_f fit_val(idx_v); best_x pop(idx_v, :); end new_pop zeros(np, nv); for i 1:2:np % 锦标赛选两个父本 p1_idx tournament(fit_val, viol, opts.tour_size); p2_idx tournament(fit_val, viol, opts.tour_size); % 自适应交叉 [c1, c2] arithmetic_cross(pop(p1_idx, :), pop(p2_idx, :), pc, rand); % 多项式变异 c1 poly_mutate(c1, lb, ub, pm, 20); c2 poly_mutate(c2, lb, ub, pm, 20); new_pop(i, :) c1; if i1 np new_pop(i1, :) c2; end end % 精英个体替换最后一个位置, 防止丢失 if ~isempty(best_x) new_pop(end, :) best_x; end pop new_pop; [fit_val, viol] eval_pop(pop, opts.eps_eq); history(gen, 1) best_f; history(gen, 2) feas_ratio; end end主循环的逻辑顺序要注意精英保存在生成新种群之前完成防止本代最优被交叉变异破坏生成完新种群后用精英个体填充最后一个位置这是固定槽位的做法。4.2 关键参数速查表与设置原则参数对改进 GA 的影响远大于对标准 GA 的影响下面按重要度排序参数推荐范围作用与调节逻辑np 种群大小50 ~ 200约束越多、变量维数越高取接近 200过大导致每代耗时显著上升maxgen 迭代代数200 ~ 1000看 history 曲线若 100 代后目标基本不动再大也没意义tour_size 锦标赛规模2 ~ 4越大选择压力越大种群收敛快但易早熟约束强时保持 2pc 交叉概率0.6 ~ 0.95自适应写法中基础值即可不追求细调pm 变异概率0.05 ~ 0.3自适应写法中随可行比例增大而增大变异概率过高会使收敛不稳eta_m 变异分布指数10 ~ 30值小变异扰动大前期可用后期想精细收敛调到 20~30eps_eq 等式约束容忍度1e-6 ~ 1e-3依据等式约束量级量纲大就放宽feas_tol 可行性判定阈值1e-6 ~ 1e-4固定值即可不必跟随 eps_eq 联动有一类高频误用值得拆开说许多人把变异概率固定设为 0.01这是二进制编码时代遗传操作风格。实数编码下变异概率定义的是“每个基因位是否发生变异”0.01 意味着一个 10 维变量的个体平均每代只有 0.1 个基因位被扰动几乎等于不变异。改进 GA 中变异概率取 0.1 以上是正常的不要跟二进制编码的设计经验混谈。4.3 收敛失败的三个常见信号与对应排查方向第一history 中 best_f 在多代内反复跳增再回落通常是精英保留机制没有生效。检查是否在循环开头使用旧的fit_val索引保存精英然后又在更新后覆盖了pop的最后一行——注意new_pop(end, :) best_x;必须在重新赋值pop new_pop之后才生效否则精英个体被新种群覆盖。第二可行解比例长期为 0。优先检查eps_eq是否过严等式约束x(1)x(2)-0.5的量级是 1如果eps_eq 1e-10算法在随机搜索阶段几乎不可能生成恰好满足该等式的个体可行解比例必然为 0。此时把eps_eq放大到 1e-3看比例是否出现抬升。第三收敛到不可行点。当best_x无法通过confun(best_x)校验时说明可行解从未被记录或精英个体被错误更新。在可行解比例极低时if min_viol feas_tol的条件会长期不满足best_f一直保持inf——这是正常的不代表死循环观察到这种现象优先调整约束优化策略而不是代码结构。5. 约束处理策略的变体从罚函数到可行性法则的适用边界5.1 罚函数法的改进动态惩罚与自适应惩罚可行性法则并非在所有场景都优于罚函数比如优化目标本身很难计算、每次评估代价极高时可行性法则迫使种群先把约束满足可能浪费大量评估预算在无效区。此时改进罚函数法是一个更务实的变体。动态惩罚的核心是让惩罚系数随代数增长F(x) f(x) (C * gen)^alpha * V(x)C和alpha的经验值是 C0.5、 alpha2。代数小惩罚对比目标函数较弱允许种群广泛探索不可行域代数大惩罚加重强制后代回到可行域。改进 GA 采用这个思路会比固定系数更早逼近最优边界。但要注意动态惩罚对f(x)和V(x)量纲比例极度敏感。如果V(x)的量级在 1e3 而f(x)在 1e-2那么再小的 C 也会让罚函数直接压过目标函数种群行为等同于极小化 V(x)。使用时务必先归一化计算初始代V(x)的均值和f(x)的均值用二者的比值校准 C。5.2 混合约束处理可行性法则 距离度量纯可行性法则的缺陷在于当可行域在搜索空间中占比极小时锦标赛中两个不可行个体比较只依据 V(x)它会引导种群走向“可行域方向”但这个方向不一定是目标函数下降最快的方向。如果可行域是狭长的弯月形种群会被 V(x) 导向可行域入口然后在入口附近因为缺乏多样性而停滞。一个常见改进是引入“约束距离”概念把 V(x) 换成一个带有梯度方向倾向的度量。比如在目标函数梯度容易获得时将目标函数轻度融合进不可行个体的比较中score V(x) beta * (iter/maxgen) * normalize(f(x))beta控制目标函数在不可行解排序中的权重随迭代代数缓慢增加。前期算法主要探索可行方向后期在可行解充足时逐渐恢复对目标函数下降的重视。这种混合策略比纯罚函数稳定比纯可行性法则收敛效率高。6. 验证改进效果与进阶自适应惩罚系数标定的一个具体办法改进 GA 是否有提升不能只看最终“找到一个可行解”至少要对比三组曲线标准 GA固定惩罚、改进 GA可行性法则、改进 GA自适应惩罚。每条曲线记录每代最优目标值加约束违反度两个维度。一个可行的快速验证脚本框架是修改ga_improved.m的参数结构固定 np100、maxgen500、tour_size2三组实验各随机运行 10 次记录成功率和平均最优值。成功率定义运行结束后confun(best_x)的总违反度小于 1e-3 且 best_f 优于 fmincon 对该问题的基准解则算一次成功。判读结果时分两种情况。如果三组都能找到可行解再比较最优值的分布如果标准 GA 失败率高于 30%说明固定惩罚系数明显不适合该约束强度改进方向是正确的。实际操作中自适应惩罚系数的初始标定有一个半自动化的小技巧先跑一次标准 GA输出初始代的平均违反度V_bar和平均目标f_bar然后取C f_bar / (V_bar * maxgen^0.5)作为动态惩罚的初始系数。这个值的物理含义是让初始代的目标与惩罚大致同量级之后随代数增长惩罚持续增强。还有一个对等式约束多的问题有效的做法值得一并收下改造交叉算子使后代尽量继承父本的线性关系。若约束里有线性等式A * x b在交叉前对父本向量做投影把两个父本减去其在零空间中的分量只保留满足等式的部分参与算术交叉。数学上这等价于对决策变量做线性变换降维变换后等式约束自动满足。实现时步骤为构造零空间基Z null(A)用Z * s表示可行解流形所有个体编码成s而不是x解出结果后再用x Z*s x0变换回去。这个办法对混合整数问题时依然有效——只要整数变量不参与被约束的维度即可。跑通这个流程后改进 GA 才算是真正把手上的约束优化问题吃透了。本文还有配套的精品资源点击获取