
很多人在学习“最优化方法”或“运筹学”时都会卡在同一种体验里课堂上能听懂拉格朗日乘子能推导单纯形表但一拿到真实问题比如工厂排产、配送路径、参数标定就不知道第一步该写什么。这个问题的根源不是数学功底不够也不是 MATLAB 操作不熟练而是缺少一种“把工程问题翻译成优化模型”的训练。做优化真正难的不是求导和迭代而是搞清楚决策变量是什么、目标函数怎么写、约束条件怎么列。一旦模型写清楚了剩下的求解工作完全可以交给 MATLAB 求解器去完成。“大谦MATLAB”这套免费教程核心方向就是最优化方法与运筹学的 MATLAB 实践。它没有把重点放在繁琐的定理证明上而是用一个又一个可运行的例子把线性规划、非线性规划、整数规划、图与网络优化讲成一个“建模 求解 验证”的完整过程。这篇文章就沿着这条主线提炼出一条适合自学的上手路径并提供可以直接运行验证的 MATLAB 代码。如果你正准备学运筹学或者已经在用 MATLAB 但只会做数据分析和绘图相信这篇文章能帮你把 MATLAB 从“计算器”变成真正的“决策优化工具”。1. 为什么最优化方法值得当成应用课来学工科学生接触最优化方法通常是从《运筹学》或《最优化方法》课程开始的。这类课程会花大量时间介绍单纯形法原理、对偶理论、KKT 条件、凸性分析这当然重要。但如果学习目标只是工程应用很容易陷入一个误区证明写了一大堆真到了用的时候还是不会建模。举一个典型的例子。工厂要安排两种产品的产量目标是利润最大但要受原材料、工时、设备容量限制。这个问题几乎每个人都能听懂可真要写成 MATLAB 代码时很多初学者会拿循环去枚举产量组合而不是先想清楚决策变量是什么答案是每种产品的产量。目标是什么答案是总利润最大化。约束是什么答案是资源使用量不超过可用量。一旦建模思路清晰就会发现 MATLAB 里的linprog只需要几行代码就能完成求解。真正困难的反而是前面的“翻译”工作。这也是“大谦MATLAB”这套免费教程给出的一条重要判断最优化方法不是一门纯数学课也不是一门纯编程课它本质上是建模课。MATLAB 在其中承担的角色不是帮你计算加减乘除而是帮你把数学模型放进成熟的求解框架中让算法细节由经过验证的求解器处理。如果你现在正面临生产调度、路径规划、资源分配、参数拟合一类的问题最应该学的内容不是“手撕算法”而是理解问题类型、选择合适求解器、看懂结果是否合理这三件事。2. 最优化方法与运筹学的关系以及问题分类先厘清概念。运筹学是一个更大的学科体系它研究的是如何在资源受限的条件下做出最优决策包括数学规划、排队论、库存论、博弈论、决策分析、图与网络等多个方向。最优化方法通常指其中以数学规划为核心的部分也就是通过目标函数、决策变量、约束条件来描述决策问题并寻找最优解的方法。用 MATLAB 去实践最优化方法首先要能判断当前问题属于哪一类因为不同问题要调用不同求解器。问题类型数学模型特征典型 MATLAB 入口典型应用场景线性规划 LP目标函数和约束条件都是线性关系变量连续linprog生产计划、运输问题、资源分配整数规划与混合整数规划 IP/MIP部分变量必须取整数或取 0-1 值intlinprog选址、指派、项目选择、调度非线性规划 NLP目标函数或约束中包含非线性项fmincon、fminunc参数估计、控制器参数优化、机械设计二次规划 QP目标函数是二次函数约束为线性quadprog投资组合、MPC 预测控制图与网络优化在节点和边构成的图上寻找最优结构graph、shortestpath等物流配送、通信路由、交通规划这个分类判断决定了你后面的代码结构。很多初学者拿到一个带整数条件的问题却直接套用fmincon结果没有遵循整数约束也有人把非线性约束关系误写成线性约束最后得到明显不符合物理直觉的结果。这些问题都可以通过问题分类来规避。3. 环境准备检查 MATLAB 优化工具箱是否可用开始运行代码之前先确认环境里是否安装了 Optimization Toolbox。MATLAB 主程序本身提供基础计算功能但linprog、fmincon、intlinprog这些函数都归属于优化工具箱没有对应许可时调用会直接报错。在 MATLAB 命令行窗口执行ver(optim)如果工具箱正常安装会显示优化工具箱的名称和版本号如果没有安装系统会提示找不到对应产品。也可以用下面这段代码确认许可状态if license(test, Optimization_Toolbox) disp(优化工具箱可用可以开始最优化方法实验。); else disp(当前环境缺少优化工具箱请先获取正版授权。); end另一个实用检查方法是看函数解析路径which linprog which fmincon which intlinprog如果每个命令都能返回一个以toolbox/optim/开头的路径说明求解器函数已经被正确加载。对于学生用户建议优先使用学校提供的正版校园授权如果暂时没有授权可以先完成建模部分等环境可用后再运行代码不要使用来路不明的破解工具。本文示例的代码逻辑在各主要 MATLAB 版本中保持稳定。部分界面和默认算法在新的版本中会发生变化不过这不影响核心建模思路。4. 从理论到 MATLAB 代码需要先建立四个习惯很多教程直接把代码贴出来初学者照着敲一遍能出结果但换个题目仍然不会。原因在于没有理解 MATLAB 优化函数背后的接口约定。这里总结四个最基础的转换习惯。4.1 约束条件要统一成“小于等于”方向linprog和fmincon接收的不等式约束默认格式都是 A x b。如果你的实际约束是大于等于关系不等式两边要同时乘以 -1。比如 x 2y 8要改写成 -x - 2y -8。这个细节看似简单却是命令行报错最多的地方之一。初学者容易直接把原始约束矩阵填进去忘了转换方向导致可行域找错。4.2 MATLAB 默认求最小值最大化要取负号MATLAB 优化问题的默认方向是最小化。举一个很常见的例子工厂问题目标是利润最大化max 40*x1 30*x2在使用linprog时必须把目标函数系数写成f [-40; -30];最终求出的fval是负的最小值因此最大利润是-fval。新手看到输出的目标值是负数常常误以为求解失败其实这是接口设计导致的正常结果。4.3 用匿名函数表示目标函数在非线性规划里目标函数通常不是简单的一次函数而是带有平方项、指数项甚至分式的函数。你可以通过匿名函数直接把目标传给求解器fun (x) 100 * (x(2) - x(1)^2)^2 (1 - x(1))^2;如果你已经有独立的函数文件也可以把函数句柄传入。区别在于匿名函数适合简单表达式复杂表达式建议写成独立函数文件便于测试和复用。4.4 搞清楚 solver-based 与 problem-based 两套风格MATLAB 优化工具箱提供了两种建模风格。一种是传统的基于求解器的风格也就是本文要演示的linprog、fmincon这类写法参数按固定顺序传入效率高网上存量代码也多。另一种是基于优化问题的风格先用变量对象构造表达式再统一调用solve。对于运筹学初学者建议先把基于求解器的写法跑通因为这种写法能够直接看到矩阵 A、向量 b 等模型要素有助于把数学建模和代码对应起来。等理解透了再去学习更适合大型通用建模的 problem-based 工作流会更顺利。5. 线性规划入门用 linprog 求解生产计划问题线性规划是运筹学里最基础也最常用的一类模型。我建议初学者把下面这个例子完整跑一遍因为麻雀虽小五脏俱全。假设某工厂生产 A、B 两种产品单位利润分别为 40 和 30。生产受到三个资源约束x1 x2 12 2*x1 x2 20 x2 8其中 x1、x2 分别表示 A、B 产品产量且产量不能为负。将目标函数写成最大化 40x1 30x2。完整 MATLAB 代码如下% 文件路径lp_production_plan.m clear; clc; % 目标函数系数MATLAB默认求最小因此最大化时取负 f [-40; -30]; % 不等式约束 A*x b A [1 1; 2 1; 0 1]; b [12; 20; 8]; % 变量下界这里没有上界所以 ub 可以留空 lb [0; 0]; ub []; % 求解线性规划 [x, fval, exitflag] linprog(f, A, b, [], [], lb, ub); % 显示结果 disp(最优产量 x ); disp(x); disp(最小化目标值 fval ); disp(fval); disp(实际最大利润 ); disp(-fval); disp(退出标志 exitflag ); disp(exitflag);代码里没有等式约束所以Aeq和beq都写成空矩阵[]。这段代码中linprog的参数顺序是固定的如果漏掉一个空矩阵后面的参数就会错位。运行后如果你看到 x 在合法范围内利润约等于 400exitflag为 1说明求解成功。exitflag是判断求解状态的第一个信号不要忽略它。为什么要关注exitflag因为它能直接告诉你这次求解是否可信。exitflag 1表示函数收敛到最优解exitflag 0表示迭代次数达到上限exitflag -2表示没有找到可行解。实际工程中看到结果第一件事不是复制数据而是检查退出标志。6. 非线性规划入门用 fmincon 处理带约束的参数优化线性规划能解决的问题依然有限。很多实际工程问题比如根据实验数据标定模型参数、设计满足强度条件的结构尺寸目标函数往往不是线性函数。这时要使用的是fmincon。这里用一个带球形约束的 Rosenbrock 函数变体来演示min 100*(x2 - x1^2)^2 (1 - x1)^2 s.t. x1^2 x2^2 1Rosenbrock 函数是优化领域里的经典测试函数它的全局最优点在一个窄长的“谷底”上如果没有约束条件最优解应为 (1, 1)。加入单位圆约束后问题变成寻找约束范围内的最优点。先定义目标函数% 文件路径nlp_constrained.m clear; clc; fun (x) 100 * (x(2) - x(1)^2)^2 (1 - x(1))^2;再定义非线性约束函数。fmincon要求约束函数的第一个输出是不等式约束 c且必须满足 c(x) 0第二个输出是等式约束 ceq本例没有等式约束所以返回空数组nonlcon (x) deal(x(1)^2 x(2)^2 - 1, []);因为约束是 x1^2 x2^2 1移项后得到 x1^2 x2^2 - 1 0因此 c 表达式中要减 1。这是非线性约束最容易写错的地方。设定初始点后调用求解器x0 [-1; 1]; [x, fval, exitflag] fmincon(fun, x0, [], [], [], [], [], [], nonlcon); disp(最优解 x ); disp(x); disp(最优目标值 fval ); disp(fval); disp(退出标志 exitflag ); disp(exitflag);之所以要从 [-1; 1] 出发是因为该点位于单位圆边界附近方便算法在可行域内搜索。非线性规划对初始点比较敏感不同初始点可能收敛到不同局部最优解。这一点与线性规划有本质区别也是很多刚入门者最容易忽略的坑。运行代码后你会得到一个位于单位圆上或圆内的点。如果尝试把初始点改成 [5; 5]求解器可能会报告找不到可行解或表现异常因为初始点到约束区域的距离可能影响算法搜索路线。在实际工程中fmincon通常用来做控制器参数优化、机械结构尺寸优化等问题。使用时的核心建议是启动前先确认约束表达式方向是否正确再确认初始点是否在合理物理范围内否则求解结果缺乏工程意义。7. 整数规划的离散决策问题intlinprog 实战先问一个问题生产计划中的产量可以是小数吗在某些场景下可以如果生产液体物料产量取连续值是合理的。但如果决策的是“要不要在某城市建仓库”“要不要上某条产线”变量就只能取 0 或 1。这种问题属于整数规划或混合整数规划。MATLAB 中求解这类问题的主入口是intlinprog。下面用一个“项目投资选择”的例子来说明。假设你只能从 4 个候选项目中选择 2 个进行投资每个项目本身的收益不同但必须选满 2 个。用 x(i) 表示第 i 个项目是否选中取值 0 或 1。目标函数希望总收益最大max 5*x1 7*x2 9*x3 8*x4 s.t. x1 x2 x3 x4 2因为 MATLAB 默认求最小化目标系数取负% 文件路径mip_project_select.m clear; clc; f [-5; -7; -9; -8]; % 所有变量都限定为整数 intcon 1:4; % 没有不等式约束因此 A、b 为空 A []; b []; % 等式约束总共选择 2 个项目 Aeq [1 1 1 1]; beq 2; % 决策变量是 0-1 变量 lb zeros(4, 1); ub ones(4, 1); % 设置显示方式避免屏幕刷屏 opts optimoptions(intlinprog, Display, final); [x, fval, exitflag] intlinprog(f, intcon, A, b, Aeq, beq, lb, ub, opts); disp(选择方案 x ); disp(x); disp(最大收益 ); disp(-fval); disp(退出标志 exitflag ); disp(exitflag);从目标系数看第 3 个项目收益最高第 2 个项目收益次高。如果只选 2 个最优解应该是选中项目 2 和 3也就是 x [0; 1; 1; 0]最大收益是 16。你可以通过这段代码验证这个结论。注意intcon表示哪些变量要求整数。本例里 4 个变量都取整所以写成1:4。二值约束由下界 0 和上界 1 给出加上整数约束就自动形成了 0-1 变量。整数规划与连续优化的一个区别是很多 MIP 问题在规模变大后求解时间会显著上升。它本质上属于离散组合优化最坏情况下复杂度很高。实际项目中如果问题规模太大建议先不要急着跑全量数据而是先用小数据验证模型逻辑再扩大规模。8. 图与网络优化使用 graph 对象求最短路径运筹学中还有一类覆盖面很广的问题就是图与网络优化。简单地说它把物流网络、交通网络、通信网络抽象成节点和边然后在上面寻找最短路径、最小生成树、最大流等结构。下面是 MATLAB 实现最短路径的示例。假设一个配送网络有 6 个节点边上的数字代表两节点之间的运输成本或距离% 文件路径graph_shortest_path.m clear; clc; % 定义边的起点、终点和权重 s [1 1 2 2 3 4 4 5]; t [2 3 3 4 5 5 6 6]; w [4 2 3 6 5 1 3 7]; % 创建无向图对象 G graph(s, t, w); % 绘制网络图 p plot(G, EdgeLabel, G.Edges.Weight); % 求解节点 1 到节点 6 的最短路径 [path, dist] shortestpath(G, 1, 6); disp(最短路径经过的节点); disp(path); disp(最短路径总长度); disp(dist); % 在图上高亮最短路径 highlight(p, path, EdgeColor, red, LineWidth, 2);在这个网络中从节点 1 到节点 6 最省成本的走法是经过节点 2 和节点 4也就是路径 [1 2 4 6]总长度为 4 6 3 13。用graph对象建模的好处是你不需要手动维护邻接矩阵只需要按边列表给出起点、终点和权重即可。shortestpath会自动选择合适的算法。对于有方向性的场景比如单向道路、单向通信链路需要把graph换成digraph并按照实际的源和目标方向定义边。绘制网络图这一步也不是可选项它能帮你直观验证边的连接关系是否符合预期。很多建模错误画一遍图就能发现。9. 最优化方法常见问题与排查方法代码跑不出结果时先不要怀疑求解器有问题。绝大多数情况下问题出在模型转换、参数顺序或约束方向上。下面整理了几个高频问题。问题现象可能原因排查方式解决方案调用linprog报错提示矩阵维度不一致约束矩阵 A 的行数不等于 b 的元素个数用size(A)和length(b)检查维度按“每个约束一行”的原则重写 A结果目标值 fval 是负数怀疑求解错误原问题是最大化代码中取了负号检查目标函数系数是否取反输出实际最优值用-fvalfmincon提示约束条件无可行解非线性约束写成大于等于方向检查非线约束函数的 c 是否满足 c 0将约束进行移项处理确保方向正确fmincon每次运行结果不一样目标函数非凸存在多个局部最优解改变初始点多次测试使用全局优化工具箱中的多起点搜索或通过实际经验设定合理初始解intlinprog返回exitflag -2整数约束下找不到可行解检查等式约束是否过强下上界是否合理松弛整数变量求解观察连续最优解的趋势代码在旧版本 MATLAB 中无法运行调用了较新版本才引入的函数查看报错函数名换成经典函数入口或改用本地支持相近的替代写法明明给了上界求解结果却超出上界上界写到了 lb 中出现位置错位对比intlinprog参数顺序按 f、intcon、A、b、Aeq、beq、lb、ub 的顺序逐一核对排查所有优化问题的第一原则都是确认数学模型本身正确。只要模型正确即使函数调用有小问题也容易通过报错提示定位如果模型本身错误再强大的求解器也只能给出一个看似合理但实际不可用的结果。10. 最优化方法工程实践与建模建议从本文的示例可以看出运行 MATLAB 求解器本身并不复杂。真正复杂的是如何把一个实际问题抽象成优化模型并保证结果能落到生产环境。这里整理几条最重要的工程实践建议。第一条写代码前先写一段注释把决策变量、目标函数、约束条件全部列出来。直接写代码很容易漏约束而注释中的模型描述是所有人理解工程问题的基础。第二条保持数据与代码分离。对于生产计划问题约束矩阵 A、向量 b 往往来自 Excel 或数据库。建议先读取数据再组装成矩阵不要在代码内部写死大量魔法数字。这样当某个资源上限发生变化时只需要改数据文件不需要改求解逻辑。第三条做灵敏度分析。求解器给出最优解之后不要急着结束。你可以把某一个约束的右侧值上下调整比如把原料上限从 20 改成 22再观察最优利润如何变化。这种扫描操作能让决策者知道哪个约束最“卡脖子”这对工程决策非常有价值。第四条注意数量级统一。如果目标函数中一个参数是一万另一个参数是零点零零一求解器内部的数值稳定性会受影响。更稳妥的做法是先完成单位归一化或者通过缩放让变量处于相近数量级。这一点对非线性规划尤其重要。第五条不要无脑接受默认算法。MATLAB 工具箱确实为多数函数设置了智能的默认选择但在特定问题中改变算法可能导致收敛速度和精度明显不同。比如linprog在不同规模问题下的默认算法可能有差异当遇到大规模稀疏问题时可以查询文档看看是否需要切换算法或开启稀疏矩阵存储。第六条永远为生产环境预留回滚和校验环节。如果优化结果用于真实的生产排程或资源分配最好在一套仿真环境里先跑一周历史数据用实际结果和优化结果做对比确认约束表达是否符合现场规则再切换到实际使用。11. 学习路线建议用“最小闭环”替代“读完再动手”到这里你已经具备了上手最优化方法的基本框架。如果你打算跟着“大谦MATLAB”这类免费教程继续学习我的建议是不要追求一次性把所有理论看完而是采用“最小闭环”的学习方式。第一步把本文第 5 到第 8 章的四个例子依次复现一遍不要复制粘贴后看看结果就结束而是亲手把 A、b、lb、ub 这些矩阵变量的维度核对一遍。第二步把每个例子的目标函数或约束条件做一次微小改动。比如把第 5 章的利润系数从 40、30 改成 60、20看最优方案会发生什么变化把第 7 章的选 2 个项目改成选 3 个项目观察求解结果和耗时。第三步尝试找来自己研究方向里的一个小问题比如电机设计中的参数选择、车辆路径规划、采购数量决策用线性规划或整数规划先建一个简化版本哪怕约束不全也要跑通一个基本可用的模型。这三个步骤完成后你对 MATLAB 中最优化方法的理解会远远超过“知道有这些函数”的阶段。你会发现运筹学课程里的很多概念比如可行域、最优解、松弛变量、整数解 gap都会在代码运行结果里变得直观起来。真正希望你记住的判断是在 MATLAB 中做最优化建模能力决定了解决问题的上限而求解器调用只决定了下限。下次打开 MATLAB先别着急写代码拿一张纸把决策变量、目标函数、约束条件写清楚这比任何算法技巧都重要。