公司动态
多目标规划与序贯算法:从矛盾目标到Matlab实战求解
1. 项目概述多目标规划与序贯算法的实战价值在数学建模竞赛和实际的科研、工程决策中我们常常会面临一个核心困境目标不止一个而且它们之间往往相互矛盾。比如在设计一款产品时我们希望它成本最低、性能最强、同时生产周期最短在规划一个城市的交通网络时我们希望建设成本最小化、通行效率最大化、环境影响最小化。这些目标很难同时达到最优因为降低成本可能意味着牺牲性能或延长工期。这就是多目标规划问题Multi-Objective Programming MOP要解决的典型场景。单纯地喊一句“我全都要”是行不通的我们需要一套系统的数学方法来处理这种“既要、又要、还要”的复杂局面。多目标规划的核心思想不是寻找一个唯一的“最优解”而是寻找一系列“折中解”也称为帕累托最优解集。在这个解集中任何一个目标的改进都必然导致至少一个其他目标的恶化。决策者可以根据自己的偏好从这个解集中挑选最合适的方案。而序贯算法则是求解这类多目标问题的一种非常直观且有效的策略。它的思路很像我们日常做决策先解决最紧迫、最重要的目标在这个目标达成的基础上再去考虑下一个目标层层递进。这种方法将复杂的多目标问题分解为一系列单目标问题来顺序求解极大地降低了问题的复杂度尤其适合目标之间有明确优先级或者决策者偏好清晰的场景。我之所以想详细聊聊这个主题是因为在带学生打数模比赛和做工业优化项目时发现很多朋友对多目标规划的理论望而生畏更不知道如何用工具比如Matlab把它实现出来。网上能找到的代码要么过于简单抽象要么和实际问题脱节。所以我打算结合一个具体的实例把从问题理解、模型建立、到用序贯法求解、最后用Matlab代码实现的完整链条走一遍。你会发现只要理解了背后的逻辑用代码把它“翻译”出来并没有想象中那么难。这篇文章适合有一定数学建模基础对优化问题感兴趣并且希望掌握一种实用求解工具的朋友。2. 核心原理拆解多目标规划与序贯法是如何工作的在深入代码之前我们必须把地基打牢。理解多目标规划的基本概念和序贯算法的运作机制是后续一切操作的前提。这部分我会尽量用通俗的类比来解释避免陷入复杂的数学公式堆砌。2.1 多目标规划的基本框架与核心挑战一个标准的多目标规划问题可以表述为Minimize F(x) [f1(x), f2(x), ..., fk(x)] Subject to: x ∈ X其中x是决策变量向量X是由各种等式和不等式约束构成的可行域。F(x)是一个包含k个目标函数的向量。注意这里的“Minimize”是对向量而言的因为各个目标可能方向不同有的要最小化如成本有的要最大化如利润通常我们会通过取负号等方式统一为最小化问题。与单目标优化追求一个“最好”的点不同多目标优化的解是一个集合——帕累托最优解集对应在目标函数空间中就是帕累托前沿。想象一下你购物既要商品质量好又要价格便宜。市场上那些“性价比高”的商品在同等价格下质量最好或在同等质量下价格最低就构成了帕累托前沿。你不可能找到一个质量最好同时又最便宜的商品那不存在。多目标规划的主要挑战就在于目标间的矛盾性改善A往往导致B变差。解的不可比性对于两个解x1和x2可能f1(x1) f1(x2) 但 f2(x1) f2(x2)无法直接判断谁优谁劣。求解复杂度高直接寻找整个帕累托前沿计算量巨大特别是对于非线性、非凸问题。因此实践中我们常常需要引入决策者的偏好信息将问题转化为可求解的形式。序贯算法就是其中一种基于优先级偏好的强有力方法。2.2 序贯算法化繁为简的层次化求解策略序贯算法的思想非常符合人类处理复杂问题的直觉分清主次逐个击破。它的核心步骤可以概括为以下几步优先级排序决策者根据重要性对k个目标函数进行排序。例如f1最重要f2次之依此类推。第一层求解将最重要目标f1(x)作为单目标优化问题求解得到其最优值f1*。但此时这个最优值可能对应着无数个解最优解集。转化为约束将第一层目标f1(x)的最优值f1*或一个接近的松弛值作为一个新的约束加入到模型中。例如添加约束f1(x) f1* δ其中δ是一个很小的正数容许偏差这保证了在求解后续目标时第一目标的表现不会退化太多。第二层求解在满足新约束即第一目标已近似最优的前提下求解第二重要的目标f2(x)。得到最优值f2*。迭代进行重复步骤3和4将已求解的目标函数最优值作为约束逐层求解下一个优先级的目标直到所有目标处理完毕。为什么这种方法有效它通过将偏好信息优先级明确地转化为数学约束将一个复杂的向量优化问题分解为一系列更简单的标量优化问题。每一步都只需要调用成熟的单目标优化算法如Matlab中的fmincon大大降低了求解难度。需要注意的关键点容许偏差δ这个值很关键。如果δ0要求后续目标必须在第一目标的精确最优解集上优化这可能导致可行域非常小甚至无解尤其当f1的最优解是孤立点时。适当放松δ 0可以给后续优化留出空间找到更平衡的解。δ的选择需要根据实际问题权衡。解的唯一性序贯法最终通常只给出一个解这个解是帕累托最优解之一它严格体现了决策者设定的优先级。如果你需要看到整个帕累托前沿的概貌序贯法就不太适合可能需要使用像NSGA-II这样的进化算法。适用场景非常适合目标有明确轻重缓急的情况比如“首先保证安全其次考虑成本最后再看效率”。提示序贯法得到的解有时被称为“字典序最优解”或“分层最优解”。它强依赖于你设定的优先级顺序。改变顺序可能会得到完全不同的最终解。3. 实例构建一个资源分配与生产计划的矛盾问题为了不让原理飘在空中我们构造一个典型的、具有冲突目标的管理优化问题。假设某工厂用两种资源R1和R2生产两种产品P1和P2。已知数据如下参数生产单位P1消耗生产单位P2消耗资源总量资源 R121100资源 R213150单位利润元64-这看起来像个简单的线性规划。但我们现在引入两个相互冲突的管理目标目标F1最大化总利润。这显然是工厂的首要经济指标。目标F2最小化资源R1的闲置率。R1是一种采购周期长、仓储成本高的关键资源管理层希望尽可能充分利用它避免资金积压和浪费。定义决策变量x1: 产品P1的产量x2: 产品P2的产量约束条件资源约束2*x1 x2 100(R1)资源约束x1 3*x2 150(R2)非负约束x1 0,x2 0目标函数F1: 最大化利润 6*x1 4*x2→ 转化为最小化f1 - (6*x1 4*x2)F2: 最小化R1闲置率。R1使用量为2*x1 x2总量为100所以闲置量为100 - (2*x1 x2)闲置率为(100 - (2*x1 x2)) / 100。因此f2 (100 - 2*x1 - x2) / 100。目标间的矛盾直观上为了最大化利润F1我们可能会倾向于多生产利润更高的P1。但P1对关键资源R1的消耗也大系数为2。如果极端追求利润可能会快速耗尽R1导致其闲置率为0但利润可能不是最高不一定。反过来为了最小化R1闲置率F2我们希望2*x1 x2尽可能接近100但这可能会迫使生产组合偏离利润最优的结构。管理层优先级设定假设经过讨论管理层认为利润最大化是首要目标在保证利润尽可能高的前提下再考虑提高R1的利用率。即第一优先级是F1最小化f1第二优先级是F2最小化f2。现在我们的多目标规划问题就明确了在给定的线性约束下按优先级顺序最小化[f1, f2]。接下来我们就用序贯算法来求解它。4. Matlab代码实现一步步将序贯法落地理论清晰了问题也定义了是时候打开Matlab把思路变成代码了。我们将严格按照序贯算法的步骤来编写。这里会用到Matlab的优化工具箱中的fmincon函数。4.1 第一步求解第一优先级目标利润最大化首先我们单独解决利润最大化这个单目标线性规划问题。这既是为了得到第一目标的最优值f1*也是为了验证我们的模型基础是否正确。%% 步骤1定义问题参数与第一目标求解 clear; clc; % 清空环境 % 定义线性规划参数 (用于 linprog标准形式min f*x) f_profit [-6, -4]; % 目标函数系数求max故取负号转为min A [2, 1; 1, 3]; % 不等式约束矩阵 b [100; 150]; % 不等式约束右侧向量 lb [0, 0]; % 变量下界 % 使用 linprog 求解最大利润问题第一目标 options optimoptions(linprog, Display, off); [x_opt_stage1, f1_val_stage1, exitflag1] linprog(f_profit, A, b, [], [], lb, [], [], options); if exitflag1 0 fprintf( 第一阶段利润最大化单独求解 \n); fprintf(最优生产计划P1产量 %.2f, P2产量 %.2f\n, x_opt_stage1(1), x_opt_stage1(2)); max_profit -f1_val_stage1; % 转回最大利润值 f1_star f1_val_stage1; % 记录第一目标最优值 f1* (已经是负利润的最小化形式) fprintf(最大利润为%.2f 元\n, max_profit); fprintf(此时资源R1使用量%.2f闲置率%.2f%%\n, ... 2*x_opt_stage1(1) x_opt_stage1(2), ... (100 - (2*x_opt_stage1(1) x_opt_stage1(2)))/100*100); else error(第一阶段线性规划求解失败); end运行这部分代码你会得到第一阶段的结果。假设我们得到最大利润为M*对应的f1* -M*。同时也知道了在这个最优利润下R1的闲置率是多少。这为我们后续引入约束提供了基准。4.2 第二步将第一目标转化为约束并求解第二目标得到f1*后我们不能苛刻地要求第二目标优化时利润一点都不能牺牲通常允许一个很小的松弛。这里我们引入一个容许偏差epsilon1。然后在新增的约束f1(x) f1* epsilon1下求解第二目标f2的最小化。%% 步骤2序贯求解 - 在保证利润近乎最优的前提下最小化R1闲置率 % 定义容许偏差 epsilon1例如允许利润比最大值少1个单位因为f1是负利润所以约束是 f1* epsilon epsilon1 1.0; % 这是一个关键参数可以根据实际情况调整 % 为 fmincon 准备第二阶段的非线性约束第一目标的约束 % 约束形式 f1(x) - f1_star - epsilon1 0 % 即 (-6*x1 -4*x2) - f1_star - epsilon1 0 % 注意f1_star 已经是负利润的最小值所以这个约束保证了 -利润 f1_star epsilon1 % 也就是 利润 - (f1_star epsilon1) 最大利润 - epsilon1 % 定义非线性约束函数 nonlcon (x) deal([(-6*x(1) -4*x(2)) - f1_star - epsilon1], []); % 非线性不等式约束非线性等式约束为空 % 定义第二目标函数R1闲置率 f2 (x) (100 - 2*x(1) - x(2)) / 100; % 设置 fmincon 的初始点可以用第一阶段的解作为初始点通常效果较好 x0 x_opt_stage1; % 调用 fmincon 求解第二阶段问题 options_fmincon optimoptions(fmincon, Display, iter, Algorithm, sqp); [x_opt_stage2, f2_val_stage2, exitflag2] fmincon(f2, x0, A, b, [], [], lb, [], nonlcon, options_fmincon); if exitflag2 0 fprintf(\n 第二阶段序贯求解结果 \n); fprintf(在利润不低于 %.2f 元最大利润为%.2f的前提下\n, - (f1_star epsilon1), max_profit); fprintf(最优生产计划P1产量 %.2f, P2产量 %.2f\n, x_opt_stage2(1), x_opt_stage2(2)); fprintf(实际利润%.2f 元\n, 6*x_opt_stage2(1) 4*x_opt_stage2(2)); fprintf(资源R1闲置率%.2f%%\n, f2_val_stage2 * 100); else error(第二阶段序贯优化求解失败); end这段代码是序贯算法的核心。fmincon函数在求解时会同时考虑原始的线性资源约束A*x b和我们新添加的非线性利润约束nonlcon。最终得到的x_opt_stage2就是在“利润几乎最优”这个前提下能使R1闲置率最小的生产方案。4.3 第三步结果可视化与对比分析数字是抽象的一图胜千言。我们将两个阶段的结果以及可能存在的其他折中点画出来可以更直观地理解序贯法做了什么。%% 步骤3可视化分析与对比 % 绘制可行域轮廓简化和两个最优解的点 figure; hold on; grid on; % 1. 绘制可行域边界通过绘制约束线围成的区域 % 约束1: 2*x1 x2 100 x1_line 0:1:50; x2_line1 100 - 2*x1_line; plot(x1_line, x2_line1, b-, LineWidth, 1.5); % 约束2: x1 3*x2 150 x2_line2 (150 - x1_line) / 3; plot(x1_line, x2_line2, r-, LineWidth, 1.5); % 非负约束由坐标轴表示 xlim([0, 70]); ylim([0, 70]); xlabel(产品P1产量 x1); ylabel(产品P2产量 x2); title(生产计划可行域与序贯法求解路径); fill([0, 50, 30, 0], [0, 0, 40, 100/3], [0.9 0.95 1], EdgeColor, none); % 粗略填充可行域 alpha(0.3); % 2. 绘制两个最优解 plot(x_opt_stage1(1), x_opt_stage1(2), ko, MarkerSize, 10, MarkerFaceColor, g); text(x_opt_stage1(1)1, x_opt_stage1(2)1, 阶段1: 最大利润点, FontSize, 9); plot(x_opt_stage2(1), x_opt_stage2(2), ks, MarkerSize, 10, MarkerFaceColor, r); text(x_opt_stage2(1)1, x_opt_stage2(2)-2, 阶段2: 序贯最优解, FontSize, 9); % 3. 绘制利润等值线可选帮助理解 % [X1, X2] meshgrid(linspace(0,70,50), linspace(0,70,50)); % Profit 6*X1 4*X2; % contour(X1, X2, Profit, 20, LineColor, [0.5 0.5 0.5], LineStyle, --); % colorbar; legend(约束1: 2x1x2100, 约束2: x13x2150, 可行域, 最大利润解, 序贯最优解, Location, best); hold off; % 控制台结果对比 fprintf(\n 方案对比总结 \n); fprintf(%-20s %-15s %-15s %-15s %-15s\n, 方案, P1产量, P2产量, 总利润(元), R1闲置率(%)); fprintf(%-20s %-15.2f %-15.2f %-15.2f %-15.2f\n, 仅最大利润, ... x_opt_stage1(1), x_opt_stage1(2), max_profit, (100 - (2*x_opt_stage1(1) x_opt_stage1(2)))/100*100); fprintf(%-20s %-15.2f %-15.2f %-15.2f %-15.2f\n, 序贯法解, ... x_opt_stage2(1), x_opt_stage2(2), 6*x_opt_stage2(1)4*x_opt_stage2(2), f2_val_stage2*100);运行完整的代码你会在命令窗口看到清晰的对比数据并在图形窗口看到一个二维平面图。图中清晰地展示了由两条约束线围成的可行域浅蓝色区域。绿色的圆点代表只追求最大利润时的解。这个点通常在可行域的某个顶点上。红色的方点代表序贯法得到的解。你会发现它可能从绿色的顶点“移动”到了某条约束边界上这个移动的方向正是在利润约束下努力减少R1闲置率即让点向2*x1x2100这条线靠近的结果。通过对比表格你可以定量地看到序贯法解在利润仅略微下降epsilon1控制的范围内的情况下显著降低了R1的闲置率。这就是多目标规划中“权衡”或“折中”的直观体现。5. 关键参数讨论与算法扩展代码跑通了但事情还没完。在实际应用中有几个关键的“旋钮”需要你根据具体情况仔细调节它们直接影响最终解的质量和合理性。5.1 容许偏差epsilon的选择艺术epsilon1是序贯法中最敏感的参数之一。它的选择不是随意的需要仔细考量epsilon1 0这是最严格的情况要求第二目标必须在第一目标的精确最优解集上优化。对于线性规划如果最大利润解是唯一的一个顶点那么可行域就缩小到了这一个点第二目标优化毫无意义解就是第一阶段解。如果最优解是一条边或一个面多重最优解那么第二目标就在这条边或这个面上优化。epsilon1 0这是更常见、更实用的设置。它给了第二目标一定的优化空间。这个值怎么定绝对量 vs 相对量可以用利润的绝对减少量如允许减少1元也可以用相对比例如允许利润比最大值低0.1%。基于问题尺度epsilon1的大小应该与第一目标函数值的量级相匹配。如果最大利润是几万元那么epsilon11允许少赚1元是合理的如果最大利润是几百元epsilon11就显得过于宽松了。试错法可以尝试不同的epsilon1观察第二目标f2的变化曲线。通常会有一个“拐点”在拐点之前稍微牺牲一点第一目标第二目标能获得很大改善过了拐点再牺牲第一目标第二目标的改善就微乎其微了。这个拐点对应的epsilon1往往是一个较好的权衡点。实操心得我通常的做法是先设epsilon10看看结果如果解没变或问题不可行再逐步增大epsilon1例如按第一目标最优值的0.1%、0.5%、1%递增并观察第二目标的变化。同时一定要把epsilon1的具体取值和含义在模型报告中写清楚因为它是你决策偏好的一部分。5.2 处理两个以上目标的通用框架我们的例子只有两个目标。对于有k (k2)个目标的问题序贯算法是一个自然的延伸。流程如下按优先级排序目标f1, f2, ..., fk。求解min f1(x)得到最优值f1*。添加约束f1(x) f1* epsilon1。在新的可行域下求解min f2(x)得到最优值f2*。添加约束f2(x) f2* epsilon2。重复此过程直到求解完第k个目标fk(x)。在Matlab中实现时你需要定义一个累积的非线性约束函数。例如在求解第i个目标时约束函数应包含前i-1个目标的约束function [c, ceq] multistage_constraints(x, f_stars, epsilons) % x: 决策变量 % f_stars: 前i-1个目标的最优值向量 % epsilons: 前i-1个目标的容许偏差向量 % 假设目标函数句柄已知可通过全局变量或嵌套函数传递 c zeros(length(f_stars), 1); for j 1:length(f_stars) c(j) objective_functions{j}(x) - f_stars(j) - epsilons(j); end ceq []; % 没有非线性等式约束 end然后在每一阶段的fmincon调用中传入当前阶段的约束函数句柄。5.3 序贯法与其他多目标求解方法的对比序贯法不是万能的了解它的优缺点和适用场景能帮助你在面对实际问题时做出正确选择。方法核心思想优点缺点适用场景序贯算法按优先级顺序将上层目标最优值加偏差后作为约束逐层求解。1. 概念直观符合决策思维。2. 将多目标问题转化为一系列单目标问题可利用成熟算法。3. 能获得一个明确的、符合偏好的解。1. 严重依赖目标优先级和容许偏差的设定。2. 通常只得到一个解无法观察整个帕累托前沿。3. 下层目标的优化空间受上层目标约束限制可能得不到好的折中。目标有明确、稳定的优先级排序决策者偏好清晰需要获得一个特定解。加权求和法为每个目标分配权重加权合并为一个单目标。1. 实现简单。2. 通过调整权重理论上可以探索前沿上不同的点。1. 权重设定困难且物理意义不明确。2. 对于非凸的帕累托前沿可能无法找到某些最优解。目标量纲可通约决策者能接受权重分配帕累托前沿是凸的。ε-约束法选择一个核心目标将其他目标转化为不等式约束。1. 能有效控制次要目标的水平。2. 比加权法更直观约束比权重好理解。1. 约束边界ε值的选择需要技巧。2. 如果核心目标选得不好可能难以求解。有一个明确的主要目标其他目标有明确的接受阈值。进化算法如NSGA-II模拟生物进化维护一个解种群通过选择、交叉、变异逼近帕累托前沿。1. 一次运行可获得一组近似帕累托最优解。2. 对问题形态凸性、连续性要求低鲁棒性强。1. 计算成本通常较高。2. 解的质量受参数种群大小、代数影响大。3. 不能保证数学上的最优性是启发式近似。需要了解整个帕累托前沿的分布问题非线性、非凸、复杂没有明确的单一偏好。如何选择如果你的问题中目标重要性差异显著并且你或你的决策者能够明确地说出“首先必须保证A在此基础上尽量提升B如果还有余地再优化C”那么序贯法是非常合适的选择。它直接、高效并且求解过程本身就体现了这种层次化的决策逻辑。6. 常见问题与实战调试技巧即使理解了原理写出了代码在实际运行中你依然可能会遇到各种问题。下面是我在多次实践中总结的一些典型问题和解决思路。6.1 求解失败或无可行解问题描述fmincon提示 “No feasible solution found” 或退出标志exitflag为负值。原因分析与排查容许偏差epsilon过小这是最常见的原因。第一阶段的最优解f1*可能对应一个很窄甚至孤点的可行域。添加约束f1(x) f1* epsilon后如果epsilon0或太小新的可行域可能为空。解决逐步增大epsilon并检查约束是否过紧。初始点x0选择不当fmincon是局部优化器初始点如果离新可行域太远可能无法收敛。解决将第一阶段的解x_opt_stage1作为第二阶段的初始点这通常是一个很好的起点。如果还不行可以尝试在可行域内随机生成多个初始点分别求解。非线性约束函数编写错误检查你的nonlcon函数。确保不等式约束c(x) 0的形式是正确的。用简单的测试点验证一下。原始问题就无解先单独检查第二目标f2在原始约束下是否有解不考虑第一目标的约束。用fmincon单独最小化f2试试。6.2 结果不敏感或变化诡异问题描述改变epsilon的值最终的解和第二个目标值f2几乎不变或者变化没有规律。原因分析与排查第一目标约束仍为主导可能epsilon设置得还是太小第二目标的优化空间极其有限。尝试设置一个更大的epsilon观察f2是否开始显著下降。第二目标本身“平坦”在满足第一目标约束的区域里第二目标函数f2(x)可能变化非常平缓导致优化器找不到明确的下降方向。检查目标函数的梯度。算法陷入局部最优fmincon默认的‘interior-point’算法对于某些问题可能效果不佳。解决尝试更换算法如‘sqp’或‘active-set’并调整优化选项如增大最大迭代次数MaxIterations和函数评估次数MaxFunctionEvaluations。options optimoptions(fmincon, Algorithm, sqp, Display, iter, ... MaxIterations, 1000, MaxFunctionEvaluations, 3000);6.3 如何处理目标函数量纲差异大的问题在我们的例子中利润单位是“元”闲置率是“百分比”量纲和数量级都不同。这在序贯法中通常不是问题因为我们是分层独立优化的。但在加权求和法中量纲差异巨大就会导致权重设置失去意义。对于序贯法量纲差异的影响主要体现在epsilon的设置上。如果你对第一目标利润设置了epsilon110允许利润少10元这个绝对量是合理的。但如果你的第二目标是“二氧化碳排放量”单位是“吨”其最优值可能在几千的水平那么你在第三阶段为它设置epsilon2时也应该考虑其自身的量级比如允许增加几十吨而不是也设为10。核心原则epsilon的设定应基于对该目标函数本身的“可接受退化程度”的理解是一个有物理或经济意义的绝对或相对值而不是一个统一的数字。6.4 从线性到非线性通用代码模板我们的实例是线性的但序贯法的威力在于它能处理非线性问题。下面提供一个更通用的、易于扩展的Matlab函数框架你可以用它来解决更复杂的问题。function [x_opt, f_vals, exitflags] sequential_optimization(objectives, priorities, constraints, x0, epsilons, lb, ub) % 序贯优化主函数 % 输入 % objectives: 细胞数组包含各个目标函数的句柄如 {(x)f1(x), (x)f2(x), ...} % priorities: 向量指定优先级顺序如 [1, 3, 2] 表示先解obj1再obj3最后obj2 % constraints: 包含A, b, Aeq, beq, nonlcon 的结构体用于fmincon % x0: 初始点 % epsilons: 向量对应每个目标的容许偏差在优先级排序后 % lb, ub: 变量上下界 % 输出 % x_opt: 最终优化解 % f_vals: 各目标函数在最终解处的值按原始顺序 % exitflags: 各阶段求解的退出标志 num_obj length(objectives); f_stars zeros(1, num_obj); exitflags zeros(1, num_obj); % 根据优先级排序重新组织目标、偏差 [~, idx] sort(priorities); sorted_obj objectives(idx); sorted_eps epsilons(idx); x_current x0; % 累积的非线性约束函数动态构建 dynamic_nonlcon (x) deal([], []); % 初始为空 for i 1:num_obj fprintf(--- 正在求解第 %d 优先级目标 (原索引 %d) ---\n, i, idx(i)); current_obj sorted_obj{i}; % 配置优化选项 opts optimoptions(fmincon, Algorithm, sqp, Display, final); % 调用 fmincon包含线性约束和动态构建的非线性约束 [x_current, f_star_i, exitflag_i] fmincon(current_obj, x_current, ... constraints.A, constraints.b, ... constraints.Aeq, constraints.beq, ... lb, ub, ... dynamic_nonlcon, opts); f_stars(i) f_star_i; exitflags(i) exitflag_i; if exitflag_i 0 warning(第 %d 阶段优化未成功完成。退出标志: %d, i, exitflag_i); end % 为下一阶段构建新的非线性约束当前目标值 最优值 容许偏差 if i num_obj % 更新动态约束函数 prev_f_stars f_stars(1:i); prev_eps sorted_eps(1:i); prev_obj_handles sorted_obj(1:i); dynamic_nonlcon (x) build_constraints(x, prev_obj_handles, prev_f_stars, prev_eps); end end x_opt x_current; % 计算所有原始目标函数在最终解处的值 f_vals zeros(1, num_obj); for j 1:num_obj f_vals(j) objectives{j}(x_opt); end fprintf(\n 序贯优化完成 \n); fprintf(最终解: %s\n, mat2str(x_opt, 4)); for j 1:num_obj fprintf(目标F%d 最终值: %.4f\n, j, f_vals(j)); end end function [c, ceq] build_constraints(x, obj_handles, f_stars, epsilons) % 构建累积的非线性不等式约束 c(x) 0 % c(j) obj_j(x) - f_star_j - epsilon_j num_con length(obj_handles); c zeros(num_con, 1); for j 1:num_con c(j) obj_handles{j}(x) - f_stars(j) - epsilons(j); end ceq []; % 无非线性等式约束 end这个模板将序贯流程封装起来你可以通过修改objectives数组来定义任意复杂的非线性目标函数通过constraints结构体传入线性和非线性约束并通过priorities和epsilons数组灵活控制优化流程。这为你解决更实际的工程优化问题提供了一个强大的起点。记住多目标规划没有唯一的正确答案序贯法提供了一种将你的决策逻辑清晰嵌入模型的系统化途径。