MATLAB 里的最优化与运筹学一直有个尴尬局面:概念好懂,模型好列,但真正要在 MATLAB 里把线性规划、整数规划、非线性规划、图论最短路、动态规划跑起来的时候,很多人会卡在“函数怎么调、目标函数怎么写、矩阵维度怎么对齐”这些非常具体的问题上。多数教程讲到单纯形法就停了,少数视频点开之后又只剩公式推导,缺少能直接跟着敲的完整代码。今天要聊的这套《大谦MATLAB:最优化方法与运筹学》正好补上这块缺口:它是一套免费的 MATLAB 教程,主线不是 MATLAB 的界面操作或画图技巧,而是把运筹学建模方法与 MATLAB 求解器结合起来,带你把教科书里的模型转成可运行脚本。
从内容定位来看,这套免费教程覆盖的应该是线性规划、整数规划、非线性规划、多目标优化、网络优化以及动态规划等典型最优化问题,同时结合运筹学里常见的运输问题、最短路问题、最大流问题、背包问题做实验演示。如果你正在准备数学建模竞赛、运筹学课程作业,或者刚进工业界需要自己完成一个优化算法原型验证,这套教程的学习价值会很高。注意一个前提:教程是免费的,不代表 MATLAB 软件本身可以绕过授权使用;后面我会单独讲环境合规与软件获取问题,这部分同样值得重视。
这篇文章会给出完整的学习路线建议,并以常规最优化课程中会出现的几个实验为示例,演示 linprog、intlinprog、fminunc、fmincon、shortestpath、maxflow 和 0-1 背包动态规划脚本该怎么写、怎么判断结果是否合理、遇到报错该怎么排查。没有真实测试环境数据,所以文中不编造“某某显卡实测占显存多少”这类信息,所有代码的输出都需要结合你本机的 MATLAB 版本来验证。如果你的目标是学最优化与运筹学并落地成 MATLAB 代码,这篇文章可以当作路线图和实验手册来用。
1. 核心能力速览
先给一份整体认知表,帮你快速判断这套教程适不适合自己。
| 能力项 | 说明 |
|---|---|
| 教程类型 | 以最优化方法与运筹学为主线的免费 MATLAB 教程 |
| 核心内容 | 线性规划、整数规划、非线性规划、图论与网络优化、动态规划、决策建模 |
| 代码水平要求 | 建议先掌握 MATLAB 基本语法,至少会写脚本和函数文件 |
| 软件环境 | 需要 MATLAB 正版许可,建议带 Optimization Toolbox;旧版本也可运行大部分基础实验 |
| 是否需要 GPU | 不需要,最优化教程以 CPU 计算为主 |
| 是否有可视化界面 | 无 WebUI,以 .m 脚本、函数文件和命令行执行为主 |
| 是否支持批量实验 | 支持,可通过脚本循环、参数扫描、并行工具箱扩展 |
| 是否有 Web API | 教程本身不涉及 API 服务,但算法可以封装成函数供其他程序调用 |
| 典型应用场景 | 运筹学课程学习、数学建模竞赛备赛、工业排产与路径规划入门、算法原型验证 |
强调几点:第一,这套教程解决的核心问题是“模型到代码”,而不是“MATLAB 入门”。如果你连矩阵索引、for 循环、函数定义都还不熟,建议先补 MATLAB 基础语法,再进入最优化部分。第二,在硬件需求上,最优化方法课程基本没有特殊门槛,能跑 MATLAB 的 CPU 主机就行,但“能做线性规划”和“能跑很大规模的整数规划”是两回事,教程里适合边学边跑的实验通常是中小规模问题。第三,从网络搜索热词来看,很大一部分 MATLAB 用户需要的其实是图像处理、Simulink 仿真、系统辨识与控制等方向的教程,这套内容的侧重点不同,它是面向“算法求解与建模”的,两者不冲突,可以互补。
2. 这套免费教程的学习路径怎么规划
最优化与运筹学在 MATLAB 里并不是一门单独的“工具箱语言”,它更像一套建模转译能力。你需要在纸面上把问题写成标准形式,然后用 MATLAB 函数去表达目标函数、约束条件和整数变量。
从常见课程体系来看,一套完整的最优化方法与运筹学 MATLAB 教程通常包含几个模块:
- 线性规划:单纯形法理论、内点法思想,以及 linprog 的标准调用方式。
- 整数规划:0-1 变量建模、分枝定界思想,以及 intlinprog 的整数变量定义。
- 非线性规划:无约束优化的梯度下降与牛顿法,有约束优化的 fminunc、fmincon。
- 网络优化:最小生成树、最短路、最大流、旅行商等图论问题。
- 动态规划:背包问题、资源分配、库存决策等,需要自己写状态转移代码。
- 决策分析与其他:多目标优化、博弈论与排队论的简单案例。
在学习时,不要把重点放在“记住函数名”上面。函数名记不住可以查文档,真正需要练的是建模能力:一个问题出现后,你能判断决策变量有哪些,目标函数怎么量化,约束是等式还是不等式,是线性还是非线性,变量是否需要取整。这套教程的最优路径应该把数学公式和 MATLAB 代码放在同一屏去看,先理解每一行代码对应公式里的哪一项,再尝试改参数看结果变化。
另外要注意,最优化教程通常会涉及算法迭代过程,比如单纯形法每一步换基、牛顿法每一步下降方向。如果只看最终一行最优值,训练效果会差很多。建议学习时打开 MATLAB 的脚本日志,将迭代数据导出成表格或绘图,观察求解器是如何收敛的。这个过程不需要很复杂的代码,但能帮你理解 solver 到底做了什么。
3. 本地环境部署与软件合规准备
在跑任何 MATLAB 最优化实验之前,先把环境理顺。这里的“环境部署”和深度学习项目的环境配置不太一样,不涉及显卡驱动或 WebUI,主要是版本、工具箱、文件路径和许可授权四件事。
3.1 MATLAB 版本与工具箱
MATLAB 的优化模块主要放在 Optimization Toolbox 和 Global Optimization Toolbox 里。教程中如果涉及遗传算法 ga、模拟退火、patternsearch,会用到全局优化工具箱;如果只是 linprog、intlinprog、fmincon、fminunc 这类基础函数,Optimization Toolbox 就够用。安装版本建议不低于 R2021a,但这不是绝对要求。你可以在 MATLAB 命令窗口执行:
ver('optim') ver('globaloptim')如果输出 Not found 或提示未安装,说明当前许可不包含对应工具箱。解决办法是在正版许可下通过 MATLAB 的 Add-On Explorer 安装工具箱,或者联系学校的 IT 部门确认校园许可证是否包含 Optimization Toolbox。
3.2 正版获取渠道与合规提醒
搜索热词里出现了一些关于“破解版”“密钥”的内容,这里明确说明:任何技术教程都不应该依赖盗版软件。MATLAB 是 MathWorks 的商业产品,推荐走以下合规途径:
- 高校师生:很多高校采购了校园版许可证,可以直接通过学校授权页面下载和激活。
- 个人学习:可以注册 MathWorks 账户申请试用版,或购买学生版、家庭版。
- 远程或实验室环境:部分搜索热词提到“MATLAB license 远程桌面打不开”,这类问题通常和浮动许可证的映射、主机识别或防火墙有关,建议联系实验室管理员或学校计算中心处理,不要尝试绕过授权机制。
- 预算非常有限的情况:GNU Octave 是 MATLAB 的主要开源替代品,很多基础脚本可以直接复用。但要注意,intlinprog、fmincon 等部分依赖 Optimization Toolbox 的场景在 Octave 中兼容性不完全一致,建议用基础线性规划实验验证后再平移。
3.3 设计可重复的最小工作目录
免费教程的代码文件往往分散在多个章节中,建议创建统一的项目目录结构。
matlab_optimization_course/ ├── data/ % 输入数据,如 txt、csv、mat 文件 ├── scripts/ % 每章实验脚本 ├── functions/ % 自己封装的模型函数 ├── results/ % 输出结果与日志 └── docs/ % 你自己的笔记和总结这种结构不复杂,但能解决两个问题:一是脚本运行过程中生成的中间文件不会污染代码目录;二是当你想批量跑多个实验时,把所有输出统一写进 results 目录,后面整理数据会省很多力气。
4. 核心实验:从建模到 MATLAB 代码
这一部分是文章的重点。每类运筹学模型我都会给一个典型实验、一段可以复制的核心代码,以及验证结果是否合理的方法。跑这些实验时,重点看 MATLAB 命令窗口的退出标志 exitflag 和迭代输出,它们是判断求解是否成功的直接信号。
4.1 实验1:线性规划与 linprog 标准形
线性规划几乎是最优化课程的起点。要调用 linprog,首先要把问题写成 MATLAB 接受的格式:
min f' * x s.t. A * x <= b Aeq * x = beq lb <= x <= ub写一个生产计划小例子:两种产品,目标最大化利润,有两道工序约束,决策变量非负。最大利润问题要转成最小化,所以 f 向量里取负号。
% 目标:max 3*x1 + 5*x2,等价于 min -3*x1 - 5*x2 f = [-3; -5]; % 约束:x1 <= 4,x2 <= 6,x1 + x2 <= 8 A = [1, 0; 0, 1; 1, 1]; b = [4; 6; 8]; lb = [0; 0]; ub = [Inf; Inf]; options = optimoptions('linprog', 'Algorithm', 'dual-simplex', 'Display', 'iter'); [x, fval, exitflag] = linprog(f, A, b, [], [], lb, ub, options); disp(x); disp(-fval); % 恢复最大利润运行后,x 是决策变量最优值,fval 是最小化目标值,-fval 就是原问题的最大利润。exitflag 为 1 表示收敛;如果 exitflag 为 -2 或 -3,说明模型不可行或问题无界,第一件事不是改求解器,而是检查约束方向是否写反。
关于 linprog 的算法选择:对于中小规模问题,默认算法通常足够。教程中如果想同时体现单纯形法和内点法的差异,可以用 optimoptions 切换 dual-simplex 或 interior-point,观察迭代次数与求解时间,这比只背结论更能理解算法差异。
4.2 实验2:0-1整数规划与 intlinprog
运筹学里很多实际问题必须引入整数变量。0-1 整数规划在 MATLAB 里用 intlinprog 求解,最关键的是 intcon 参数,它表示哪些变量必须取整。注意 intcon 填的是变量下标,例如第 1、2 个变量需要取整,就写成intcon = [1, 2]。
举一个常见的项目选择问题:有 10 个可能的投资项目,每个项目有成本与收益,总预算 70 万,每个项目选或不选。
f = -[100; 80; 60; 90; 120; 50; 70; 110; 40; 95]; % 负号求最大收益 cost = [15; 20; 10; 18; 30; 8; 14; 25; 7; 22]; % 预算约束:总成本 <= 70 A = cost'; b = 70; % 0-1 整数变量 intcon = 1:10; lb = zeros(10, 1); ub = ones(10, 1); [x, fval, exitflag] = intlinprog(f, intcon, A, b, [], [], lb, ub); disp(x'); disp(-fval);运行后,x 中接近 1 的变量就是被选中的项目。exitflag 为 1 表示找到整数最优解;如果模型过大,求解时间很长,可以设置 options 里的相对间隙容忍度,得到一个次优但带有间隙保证的解。这一个操作在很多教程中不会详细展开,但实际工程里非常常用:
options = optimoptions('intlinprog', 'RelativeGapTolerance', 0.05); [x, fval] = intlinprog(f, intcon, A, b, [], [], lb, ub, options);整数规划还有一个常见坑:明明定义了整数变量,求出来的结果却是小数。这通常是因为 intcon 没有写完整,或者求解器被切换到了非整数算法分支。检查 intcon 与你自己的变量编号是否一一对应,是最快的排查路径。
4.3 实验3:无约束与有约束非线性规划
非线性规划比线性规划更难的一点,是初始点选择往往影响收敛结果。MATLAB 中无约束最小化常用 fminunc,有约束最小化常用 fmincon。先看无约束情况,用一个经典测试函数 Rosenbrock 函数:
function y = rosenbrock(x) y = 100 * (x(2) - x(1)^2)^2 + (1 - x(1))^2; end在主脚本中调用:
x0 = [-1.2, 1]; options = optimoptions('fminunc', 'Algorithm', 'quasi-newton', 'Display', 'iter'); [x, fval, exitflag] = fminunc(@rosenbrock, x0, options); disp(x); disp(fval);这个函数有全局最小值点 (1, 1),fval 应该接近 0。如果从不同初始点出发,观察迭代路径和收敛情况,就能理解局部最优陷阱的含义。
有约束非线性规划更贴近运筹学实际。fmincon 的约束形式为c(x) <= 0和ceq(x) = 0,这里的 c 和 ceq 必须写成列向量。示例约束如下:
function [c, ceq] = constraints(x) % 不等式约束:x1*x2 <= 10 c = x(1)*x(2) - 10; % 等式约束:x1 + x2 = 8 ceq = x(1) + x(2) - 8; end主脚本调用:
fun = @(x) x(1)^2 + x(2)^2; x0 = [0, 0]; A = []; b = []; Aeq = []; beq = []; lb = []; ub = []; options = optimoptions('fmincon', 'Display', 'iter'); [x, fval, exitflag] = fmincon(fun, x0, A, b, Aeq, beq, lb, ub, @constraints, options); disp(x);教程在学习这一块时,建议自己改一改约束右侧常数,比如把x1+x2=8改成x1+x2=5,观察最优点的移动方向。通过这种参数敏感性实验,你对约束条件的理解会比只看课件深刻得多。
4.4 实验4:图论最短路与最大流
图论与网络优化在运筹学课程中必不可少。MATLAB 从 R2015b 之后推荐使用 graph 和 digraph 对象处理网络问题。最短路问题用 shortestpath,最大流问题用 maxflow。
构造一个有向图,节点 1 到 5 求最短路:
s = [1 1 2 2 3 3 4]; t = [2 3 4 5 4 5 5]; w = [2 6 1 3 5 2 1]; G = digraph(s, t, w); [path, dist] = shortestpath(G, 1, 5); disp(path); disp(dist); p = plot(G, 'EdgeLabel', G.Edges.Weight); highlight(p, path, 'EdgeColor', 'r', 'LineWidth', 2);运行结果会输出从节点 1 到节点 5 的最短路径节点序列和总距离。代码里 plot 画出来的图能直观看到红色路径,适合做作业或报告配图。求解最大流问题也有现成函数:
S = digraph([1 1 2 2 3], [2 3 3 4 4], [10 5 8 4 7]); [mf, ~] = maxflow(S, 1, 4); disp(mf);在图论实验里,最容易遇到的错误是节点编号没有连续、图中存在孤立节点、或者 weight 列表与边列表长度不一致。MATLAB 的 graph 对象对这类问题往往不会直接报错,而是在运行时得到错误路径,所以建议用numedges和numnodes检查建图后的基本统计量,确认图的规模符合预期。
4.5 实验5:动态规划与0-1背包问题
动态规划在 MATLAB 中没有统一的“DP 函数”,而是要求你自己定义状态和转移方程。这也是很多学习者在运筹学入门时感觉最难的部分:数学上理解递推式没问题,一写代码就不知道怎么存状态。
以一个典型的 0-1 背包问题为例,容量 W=8,物品重量与价值如下。用一维 dp 数组,容量倒序更新,避免同一物品被重复选择。
weights = [2; 3; 4; 5]; values = [3; 4; 5; 6]; W = 8; dp = zeros(W + 1, 1); for i = 1:length(weights) for cap = W:-1:weights(i) dp(cap + 1) = max(dp(cap + 1), ... dp(cap - weights(i) + 1) + values(i)); end end best = max(dp); disp(best);代码中 dp(cap+1) 表示容量 cap 时能达到的最大价值,因为 MATLAB 数组索引必须从 1 开始,所有容量都要加 1。内层循环从 W 倒着走到 weights(i),保证每个物品只放一次。如果运行后 best 等于 9,说明不超过容量 8 的最大价值是 9,这个结果可以用手算核对。
动态规划的代码量通常不大,但状态定义、循环方向、索引偏移这三处最容易出错。写完后先用一个手算能算出来的小例子测试,确认正确后再把数据规模放大。这套方法适用于后面的生产库存决策、资源分配、路径规划等更复杂 DP 问题。
5. 批量任务与脚本化:把实验变成参数扫描
学习过程中做参数敏感性分析是理解最优化算法的重要方式。你可以把单一实验改造成批量脚本,例如固定一个线性规划问题的结构,扫描不同右侧资源向量 b 下的最优值,观察资源增加带来的收益是否递减。
下面是一个完整的参数扫描例子。目标函数与约束矩阵保持不变,把第一个资源量 b(1) 从 10 扫描到 30,每条记录输出资源量与最优值。
f = [-3; -5]; A = [1, 0; 0, 1; 1, 1]; b1Set = linspace(10, 30, 20); results = zeros(length(b1Set), 2); for i = 1:length(b1Set) b = [b1Set(i); 6; 8]; [x, fval, exitflag] = linprog(f, A, b, [], [], [0; 0], []); if exitflag > 0 results(i, 1) = b1Set(i); results(i, 2) = -fval; end end T = array2table(results, 'VariableNames', {'Resource_1', 'MaxProfit'}); writetable(T, 'results/sensitivity_analysis.csv'); disp(T);这段代码体现了批量任务的工程化思路:把实验逻辑写进循环,采集结果到表格,最后用 writetable 导出 CSV。之后你想绘图,可以直接读 CSV 进 MATLAB,也可以导入 Excel、Python 做进一步分析。教程中如果只单独跑一次 linprog,很难看到资源约束变化带来的边际效应;改成批量扫描后,问题结构就清楚了。
在 MATLAB 里做批量实验时,有几个值得肯定的习惯:
- 所有结果先收集到 table,最后一次性写入文件,避免在循环里反复读写磁盘。
- 循环体内避免清空工作区,不要调用
clear或close all,否则会拖慢循环或把之前的结果清掉。 - 多组实验耗时较长时,可以把普通 for 循环改成 parfor,但 parfor 需要 Parallel Computing Toolbox,且循环体内部不适合动态图窗更新。
- 如果某个迭代中的模型不可行,用 exitflag 判断并跳过,不要在循环里报错终止整个任务。
你可能看到这里会觉得“这不就是写个循环吗”,确实,基础批量任务并不复杂。但很多 MATLAB 学习者的第一版脚本往往是在命令窗口手动改参数、手动复制结果,既容易记错实验组,又难复现。把参数扫描脚本留下,之后不管怎么改 b 或 A,都能在几分钟之内重跑一遍。
6. 功能测试与效果验证方法
学习最优化课程,怎么判断你的代码真的算对了?不能只看“程序没报错”。这里给出几个适合自己检查效果的验证手段,同样适用于免费教程配套习题。
6.1 用 exitflag 判断求解状态
MATLAB 的优化函数普遍会返回 exitflag,它是最直接的求解状态信号。例如 linprog 的 exitflag 为 1 表示收敛,0 表示达到最大迭代次数,-2 表示模型不可行,-3 表示问题无界。intlinprog 的退出标志含义略有不同,建议运行后help intlinprog或打开官方文档确认当前版本的解释。
6.2 用最优解代入约束做合法性检查
获得 x 后,把 x 代回A*x、Aeq*x,逐条核对是否满足约束。这个检查甚至不需要写额外函数,直接在工作区里执行:
check = A * x; disp([b, check]);右边一列如果全部小于等于左边一列,说明可行域满足。对等式约束,再用类似方式计算Aeq*x与beq的差值,通常允许极小的数值误差。
6.3 用数值迭代可视化观察收敛过程
非线性规划中,可以把每次迭代的输出打开,观察目标函数是否持续下降。举个例子:
options = optimoptions('fminunc', 'Display', 'iter');命令窗口里会逐次打印迭代数、函数值、步长和一阶最优性指标。如果函数值剧烈波动或长期不下降,说明初始点、步长或算法参数不理想,而不是函数本身写错。
6.4 与解析解或枚举结果对比
小型线性规划最好随手写一个暴力枚举脚本做交叉验证。0-1 背包问题规模较小时,也可以直接用 combvec 枚举所有组合,把最优值与 DP 结果对比。手工验证能发现很多看起来合理、实际上把约束方向写反的低级错误。
7. 常见问题与排查方法
学习这套 MATLAB 最优化教程时,最容易踩的坑往往不在数学,而在代码环境、函数用法和矩阵操作。下面给出一个高频问题排查表。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| MATLAB 安装后一闪就没了 | 许可未激活或图形界面初始化异常 | 查看安装日志,尝试命令行启动matlab -desktop | 确认正版许可,重新登录 MathWorks 账户,联系学校/企业管理员 |
| 提示 license 相关错误 | 许可证过期、远程桌面映射问题或浮动许可证连接失败 | 检查 license 文件与服务器地址 | 走正版激活流程,不要尝试绕过授权 |
| 运行 linprog 提示未定义函数 | 当前许可没有 Optimization Toolbox | 执行ver('optim')查看工具箱状态 | 在 Add-On Explorer 中安装工具箱,或改用支持该工具箱的许可 |
| 矩阵维度必须一致 | A 的列数与 x 长度不一致,或 x 与 y 相乘时忘了加. | 查看报错所在行,检查 size(A) 和 length(f) | 用.*做逐元素乘法,用*做矩阵乘法 |
| intlinprog 结果仍是小数 | intcon 写错或变量上下界没设置 | 打印 intcon、lb、ub 验证 | 修改 intcon 为需要取整的变量下标 |
| 约束方向反了,结果明显不合理 | 建模时将>=约束直接写进A*x <= b,不记得两边乘 -1 | 把约束列出来与代码比较 | 大于等于号约束改写为-A*x <= -b |
| 非线性约束一直不满足 | fmincon 的约束方向写反 | 检查 c(x) 是否确实满足c<=0,ceq 是否为 0 | 将 c 写成“左侧减右侧”,等式写成“左侧减右侧=0” |
| 动态规划结果偏大 | 0-1 背包内层循环没有倒序更新 | 打印每个物品更新后的 dp 数组 | 将容量循环改为从大到小 |
| MATLAB 窗口卡死 | 模型规模大、循环嵌套重或求解器迭代次数过高 | 打开任务管理器观察 CPU 和内存 | 设置最大迭代次数,或改用稀疏矩阵与优化算法参数 |
| 图的最短路结果明显绕路 | 边权重单位或符号错误 | 检查 G.Edges.Weight | 确认负权边在算法前提内,使用适合负权边的算法时需单独判断 |
这套排查逻辑不只适用于这份教程:遇到 MATLAB 报错,先读最后一行错误信息,看是函数缺失、语法错误还是变量维度问题;再看运行环境的工具箱状态;最后检查模型本身的约束方向与索引。
8. 资源占用与性能观察
最优化方法课程里,处理大规模线性规划、整数规划或图论问题时,性能观察的重点不是 GPU 显存,而是 CPU 计算时间、内存占用和求解器迭代次数。三条建议:
第一,优先使用稀疏矩阵。线性规划约束矩阵很多时候有大量零元素。用 sparse 存储可以显著减少内存,提高 linprog 内部迭代效率:
A = sparse(A);不过小规模测试里稀疏化带来的提升不明显,甚至可能被转换开销抵消。当问题规模上千行、上千列时,再考虑使用 sparse。
第二,用 tic/toc 或者 timeit 记录求解时间。比如在同一脚本里比较 dual-simplex 与 interior-point 两种算法的耗时:
options1 = optimoptions('linprog', 'Algorithm', 'dual-simplex'); options2 = optimoptions('linprog', 'Algorithm', 'interior-point'); tic; [x1, ~, exit1] = linprog(f, A, b, [], [], lb, ub, options1); t1 = toc; tic; [x2, ~, exit2] = linprog(f, A, b, [], [], lb, ub, options2); t2 = toc; fprintf('dual-simplex: %.4f s\n', t1); fprintf('interior-point: %.4f s\n', t2);实际耗时以你的机器跑出来的结果为准,不同版本、不同规模下两种算法表现可能完全相反。这个方法的主要意义是教你用计时工具评估算法,而不是背一个固定结论。
第三,观察迭代输出。Display 参数设置成 'iter' 后,MATLAB 会打印迭代信息。如果迭代数超过几百且目标函数下降非常缓慢,可以考虑调整 TolFun、TolX、MaxIterations 等求解器参数,或者降低模型精度要求。整数规划出现求解时间过长时,通常的方法是设置相对间隙容忍度,换取一个可接受范围内的次优解。整个过程应该像做实验一样去记录参数与效果,而不是每次遇到大规模问题就无脑换工具箱。
9. 最佳实践与合规提醒
从学习方法到工程落地,这里整理几条实用的建议,让这份免费 MATLAB 教程真正转化为你的建模能力。
第一,保持一批最小可运行脚本。每学习一个算法,保留一段最简单、能直接运行的 .m 文件。之后任何一个新问题,都尽量拆解成“目标函数部分 + 约束部分 + 调用求解器部分”,用这些最小样例作为起点去改写,比从空脚本开始更高效。
第二,模型文件、输入数据和输出结果分目录管理。这个建议已经在环境准备里说过,实际操作时可以把同一次实验的输入 CSV、输出 CSV 和绘图 PNG 都放到同一批文件夹中。文件名里加日期时间戳会更好:
filename = sprintf('results/result_%s.csv', datetime('now', 'Format', 'yyyyMMdd_HHmmss')); writetable(T, filename);第三,批量任务一定做日志与结果落盘。循环跑几十组参数时,如果中途报错,至少已经从前面各组中拿到了部分结果。在脚本里用 try-catch 捕获异常并把错误信息记录到日志文件,比让整个脚本中断更实用。
logFid = fopen('results/run_log.txt', 'a+'); for i = 1:20 try % 运行模型 catch ME fprintf(logFid, 'Iter %d failed: %s\n', i, ME.message); end end fclose(logFId);第四,注意版权与隐私合规。免费的方法论教程不等于软件和素材可以随意使用。MATLAB 软件请使用学校、单位或个人正版许可;课程代码如果直接用于论文或报告,应当注明参考来源;如果使用别人的人脸、声音、文本或商业数据做建模演示,必须获得授权。尤其当运筹学模型涉及真实企业排产、运输路径、人员调度数据时,不要在公开教程中贴出可识别的敏感业务数据。
第五,做结果复核。对任何“看起来最优”的方案,都要再做一次合理性检验。工业场景里的最优解不一定能直接执行:设备是否空闲、人员是否可用、交付批次是否满足实际业务流程,这些额外约束是教科书模型里通常不会出现的。运筹学学习的价值并不只是调一个 solver,而是理解模型边界,知道什么时候模型不够用,能补充约束后重新建模。
10. 总结与下一步
这套《大谦MATLAB:最优化方法与运筹学》最值得尝试的地方,是把“运筹学模型”和“MATLAB 可执行代码”之间的翻译过程讲清楚。它非常适合作为自学路线图来使用:先跟着实验把线性规划、整数规划、非线性规划、图论和动态规划跑通,再回到教材里补数学推导,你会发现自己对单纯形法、分支定界、KKT 条件的理解会落到代码层面,而不是停留在公式表面。
最先建议验证的三个功能也是最容易踩坑的三个点:第一,确认 Optimization Toolbox 可用,这是 linprog、fmincon 这类函数能运行的前提;第二,把线性规划约束的方向与 MATLAB 规定的A*x <= b对齐;第三,记住 MATLAB 索引从 1 开始,动态规划、整数变量定义里写错索引非常隐蔽,但排查起来很浪费时间。
跑完基础实验之后,下一步可以往三个方向扩展:一是多目标优化与 Pareto 前沿,比如用 gamultiobj 观察多个目标之间的权衡;二是把优化模型接到仿真流程里,用 MATLAB 脚本驱动 Simulink 仿真做参数优化,这比较贴近工程调度与控制系统设计;三是尝试更大规模的数据实例,配合稀疏矩阵、并行池、求解器选项做算法对比。带着这套免费教程打底,你后续学习真实工业案例时就不会再对“建模—求解—验证”的流程感到陌生了。建议先收藏这篇文章,装好环境,把第一个 linprog 跑通再说。