简介:北航最优化理论与方法课程学习资料包,系统整合线性规划、非线性规划、整数规划、动态规划、随机规划等核心分支,配有单纯形法、内点法、遗传算法、模拟退火、蚁群算法等方法讲解,适合数学基础较好、准备系统学习或备考的高年级本科生、研究生及工程技术人员。压缩包共96个文件、容量约108.25MB,主体为51份PDF讲义与拓展阅读、32个Matlab脚本和6份PPT课件,另有Notebook、Markdown笔记及作业说明等文本材料,按课件、作业、大作业、往年试题、教师推荐阅读等模块清晰分类,目前已有122人学习/下载。课程包并非简单课件堆叠,而是涵盖了课件讲义、Matlab程序设计、作业题与解答说明、期中期末试卷及延伸阅读书目(如Boyd凸优化课件、Sauer数值分析等),并突出航天器轨迹优化、航空网络、电力系统等实际应用场景;配合源码与大作业说明,便于读者边学边练,快速建立从建模、算法到实际求解的完整能力链条。
1. 拿到压缩包之后:先别急着双击,这个 .7z 里装着什么
拿到北航最优化理论与方法.7z这个压缩包的人,多半是刚进实验室的研究生,或者在做算法优化时想补理论基础的工程师。文件名里的.7z不是随便选的扩展名,它决定了你第一步不是双击,而是先确认系统里有没有能解压它的工具;而“最优化理论与方法”这门课,决定了第二步不是解压完就结束,而是要把几十个 PDF、PPT 和脚本理出一条能照着学的主线。这篇笔记不替你把课上一遍,而是把“拿到压缩包到真正学会”之间的路讲透:在哪解压、参数怎么设、文件怎么归类、代码怎么跑、哪些地方最容易翻车。适合拿到资料还没头绪的同学,也适合想快速把资料转成可运行代码的工程师。
2. 解压这一关:在 Linux 与 Windows 下处理 7z 文件的命令和关键参数
2.1 7z 格式为什么是课程资料打包的首选:压缩率、加密与分卷
课程资料包里最常见的东西是 PDF 讲义、PPT 课件、习题扫描件和代码文件,这些文件的文本和结构化程度很高,压缩空间比视频和照片大得多。7z 格式默认使用 LZMA2 算法,对这种以文本为主的资料包,压出来的体积比 zip 肉眼可见地小一圈。第二个原因是 7z 支持 AES-256 加密,并且可以连文件名一起加密;第三个原因是分卷,资料一大,打包的人会把包切成xxx.7z.001、xxx.7z.002这种分卷文件,方便切碎传输。这三个特性叠加起来,课程资料以 7z 形式流传就成了常态。zip 虽然更通用,但压缩率和加密能力都比不上,遇到分卷更是麻烦。
我一般拿到任何.7z文件,不会立刻解压,而是先做三件事:确认扩展名完整、看包内列表、再决定用哪个工具解压。这十几秒的检查能省掉后面一小时的排错。
2.2 Windows 下解压:7-Zip、Bandizip 与右键菜单的三个选项
Windows 上最稳妥的解压软件还是 7-Zip。安装之后,右键压缩包会出现“7-Zip”菜单,里面有“解压到当前文件夹”和“解压到北航最优化理论与方法\”两个常用项。前者会把包内所有文件直接摊到当前目录,后者会先建一个同名文件夹再解压。处理课程资料我永远选后者,因为这类包内部往往有十几层目录,直接摊开会让文件夹瞬间变得没法看。
如果用的是 Bandizip 这类带侧边栏的解压软件,解压之前就能在窗口左侧看到压缩文件树,包内有哪些目录、哪个文件大、是不是套了多层压缩包,一眼就能扫出来。这个功能在文件很多时比命令行直观得多。Windows 11 较新版本自带的资源管理器已经能直接解压普通 7z 包,但分卷、加密和损坏恢复的支持很不完整,真遇到带密码或分卷的资料,还是老实装一个专用解压软件比较省心。
2.3 Linux 下解压 7z 文件:p7zip 一条命令加三个必懂参数
Linux 默认不带 7z 命令,需要先装 p7zip-full。Debian 系发行版直接:
sudo apt install p7zip-full装完先别急着解压,用列表模式看一眼包内结构:
7z l 北航最优化理论与方法.7z然后解压到指定目录:
7z x 北航最优化理论与方法.7z -o./最优化课程 -y这里三个参数要记清楚。l是 list,只列出包内文件树不解压;x是 extract,解压并保留包内的目录结构;-o指定输出目录,注意-o后面直接跟路径,不能加空格,目录不存在时会自动创建。最后的-y表示遇到覆盖确认时全部选是,跑批处理时不用人守着。
提示:别用
e代替x来解压这类带章节目录的包。e会把所有文件拍平到同一目录,几十个文件同名互相覆盖的时候,你连翻车现场都看不懂。
如果你拿到的是分卷包,比如北航最优化理论与方法.7z.001,命令行解压方式不变,仍然解压.001开头那个文件就行,但要保证所有分卷都在同一个目录里,文件名也不能改。少了任何一个分卷,解压到对应位置就会报错。
2.4 macOS 下的解压做法与分卷包的识别
macOS 上最常见的做法是安装 The Unarchiver 或 Keka,图形界面处理单层 7z 和 zip 都够用。习惯命令行的可以用 Homebrew 装 p7zip:
brew install p7zip之后命令跟 Linux 完全一致,7z x加-o指定目录。macOS 上遇到分卷包时,图形工具往往只认主文件,把.001、.002全部拖进同一个文件夹,再双击.001一般就能自动合并解压。如果双击后提示文件已损坏,不要立刻怀疑包坏了,先检查分卷是否齐全,分卷缺一个后面全白搭。
2.5 解压前先看包内结构:用文件树发现套娃包和加密包
很多课程资料包实际上是“套娃包”:外层是 7z,里面还有 zip、rar 甚至另一个 7z。如果你直接解压,得到的是一个压缩包套另一个压缩包的奇观。所以解压前先列文件树,这一步能省掉大量重复工作。命令行用7z l,图形工具用侧边栏压缩文件树,都能在解压前看到这包到底有几层,里面是直接放 PDF,还是先放了一个“课件.zip”又一个“视频.7z”。
列目录时顺便看两个标记:文件名后面带星号或者属性列带特殊符号的,通常是加密条目;列表里出现.001、.002后缀,说明是分卷。这两种情况都要在解压前心里有数,别等解压到一半才反应过来说怎么又弹密码框了——那不是输错密码,是这包从一开始就是加密的。
3. 解压后的整理:把散装课件归成能照着学的目录结构
3.1 一眼识别包内四类文件:讲义、习题、代码、参考
解压完成后,你面对的通常是一堆名字没什么规律的文件。先别急着读,把文件分成四类。第一类是讲义和课件,文件名常带lecture、chap、课件、讲义字样;第二类是习题和作业,常见关键词是assignment、homework、作业、习题、exam;第三类是代码,看扩展名.m、.py、.ipynb、.c;第四类是参考材料,包括补充论文、参考书扫描件、往年题整理,特征词是reference、ref、paper、参考。有些包里还会有一份 README 或者课程大纲,这是最重要的文件,先单独拎出来放最外层。
分类的目的是建立学习顺序,不是做图书馆编目。课件和讲义是主线,习题是验证,代码是实验,参考材料是遇到不懂的地方才翻的工具书。这个顺序想清楚之后,目录结构就好定了。
3.2 建目录骨架:数字前缀排序,别信“自己记得住”
直接在解压目录里建这样一套结构:
最优化理论与方法/ ├─ 0_讲义/ ├─ 1_习题/ ├─ 2_代码/ ├─ 3_参考/ └─ README.md数字前缀不是摆设。文件管理器默认按名称排序,0_开头的目录会排在最前面,打开文件夹第一眼看到的就是讲义,而不是一堆名字乱七八糟的 PDF 摊在眼前。我不建议在解压目录里直接移动文件,而是先把这套骨架建好,再往里放东西。
为什么强调这个步骤?因为人脑对“我记得在第几个文件夹里”这件事的信任度远低于实际。课程资料一周后你还会打开,一个月后可能还要翻出来查某个定理,没有清晰目录结构的话,每次都要重新解压一次,等于每次都要浪费时间。
3.3 用 shell 脚本按扩展名和关键词自动归类散装文件
文件数量上去了,手拖文件不现实。我一般会写一个一次性用的 bash 脚本,按关键词和扩展名批量归类。下面的脚本按需改关键词就行:
#!/usr/bin/env bash shopt -s nullglob base="最优化理论与方法" mkdir -p "$base"/{0_讲义,1_习题,2_代码,3_参考} for f in "$base"/*.pdf; do case "$f" in *讲义*|*课件*|*lecture*|*chap*) mv "$f" "$base/0_讲义/" ;; *习题*|*作业*|*homework*|*assignment*|*exam*) mv "$f" "$base/1_习题/" ;; *) mv "$f" "$base/3_参考/" ;; esac done for ext in m py ipynb c cpp; do for f in "$base"/*."$ext"; do mv "$f" "$base/2_代码/" done done脚本开头那行shopt -s nullglob很关键。没有它,bash 在找不到匹配文件时会把*.pdf当作字面文件名传给 mv,轻则报错,重则把不存在的文件名当参数导致逻辑错乱。case语句里用*通配符做关键词匹配,注意这里的匹配对文件名大小写敏感,如果压缩包里的文件名是Chapter01.pdf而关键词写的是chap,那就匹配不上。英文关键词最好同时写小写和大写两种,或者先看一眼7z l的输出再改脚本。
代码文件用扩展名归类是够用的,但如果包里只有 MATLAB 的.m文件,那就全部进2_代码/,不用再细分。真正需要细分的是讲义:如果文件名里带了数字编号,建议保留原文件名不要改,因为后面的章节顺序全依赖这些编号。
3.4 解压后必写 README 索引:给自己留一张地图
整理完目录,花十分钟写一个精简的 README,放在最外层目录,内容就记三件事:这份资料讲了什么主线,代码需要什么环境,你打算先看哪块。一个可以用 Markdown 写的模板:
# 最优化理论与方法 ## 内容 - 0_讲义:课件与讲义,按文件名编号阅读 - 1_习题:作业与往年题,配合 0_讲义 使用 - 2_代码:MATLAB/Python 脚本,环境要求见下 - 3_参考:补充论文与参考书扫描件 ## 代码环境 - Python 3 + numpy + scipy - MATLAB R2020a 或 Octave ## 学习计划 - 第一周:无约束优化(梯度下降、牛顿法) - 第二周:约束优化(KKT、罚函数) - 第三周:线性规划与对偶写 README 不是形式主义,是为了让你三个星期后重新打开这个文件夹时,不用从文件管理器里一个个猜文件名。这个文件夹就是你的最小工作台,README 是工作台的第一层抽屉。
4. 知识体系梳理:从讲义和代码中串起最优化理论与方法的主线
4.1 先判断这份资料的主线是理论还是算法
打开0_讲义/里的第一份课件,看目录结构。如果第一章在讲凸集、凸函数和凸规划,那这门课的主线是凸优化加非线性规划,算法的部分偏后;如果第一章直接就是从单纯形表开始的,那线性规划占大头,后面的非线性部分可能是补充。最优化理论与方法在工科研究生培养里通常是先把无约束优化讲透,再引入约束,最后才讲线性规划和对偶,所以你的学习顺序也应该按这个节奏走。
判断主线还有一个快捷方式:看代码目录里.m和.py文件用了什么函数。如果大量出现fmincon、linprog这类优化求解器,说明课程重视“用现成工具解问题”;如果大量出现自己写的梯度下降、牛顿法循环,说明课程重视算法原理和实现。这两种侧重点对应的学习策略完全不同:前者你要重点弄懂每个求解器的入参出参和适用条件;后者你要能徒手把迭代公式写出来。
4.2 无约束优化:梯度下降、步长回溯与拟牛顿法的验证路径
无约束优化是最优化理论的地基。课件一般会按这个顺序展开:一维搜索(黄金分割、Armijo 回溯)→ 梯度下降 → 最速下降 → 牛顿法 → 拟牛顿(BFGS、L-BFGS)→ 共轭梯度。理解这条线的关键不是背公式,而是知道每一步在解决上一个方法的什么缺陷。梯度下降实现简单但收敛慢,尤其在有病态条件数的 Rosenbrock 函数上会剧烈震荡;牛顿法收敛快但要算 Hessian 矩阵,代价高;拟牛顿用梯度差近似 Hessian,是精度和计算量的折中。
验证理解最直接的办法是自己实现一次梯度下降,再和 scipy 的成熟实现对比。拿课程练习里最常见的 Rosenbrock 函数:
import numpy as np from scipy.optimize import minimize def rosen(x): return 100 * (x[1] - x[0] ** 2) ** 2 + (1 - x[0]) ** 2 res = minimize(rosen, np.array([-1.2, 1.0]), method="BFGS") print(res.x)这个例子用 BFGS 方法求解,初始点[-1.2, 1.0]是讲义里常用的测试起点。把method换成"CG"或"Nelder-Mead",看迭代路径和结果差异,比背诵十页收敛性定理都管用。重点不是会调 scipy,而是能解释清楚为什么不同方法在同一个问题上表现不同。
4.3 约束优化:KKT 条件、罚函数与增广拉格朗日怎么落地
约束优化部分是很多人的分水岭。讲义里会出现拉格朗日函数、KKT 条件、外点罚函数、内点罚函数、增广拉格朗日法、SQP 这些概念,光看公式很容易晕。我的经验是:不要试图一次看懂全部推导,先盯住一个具体的带约束小问题,把 KKT 条件的每个式子对照着写一遍。
比如讲义里常出现的一个简单例子:最小化x1^2 + x2^2,约束是x1 + x2 >= 1。你可以写出拉格朗日函数,解 KKT 方程得到候选点,然后用数值方法验证。scipy 里面对应的做法是 SLSQP:
from scipy.optimize import minimize fun = lambda x: x[0] ** 2 + x[1] ** 2 cons = {"type": "ineq", "fun": lambda x: x[0] + x[1] - 1} res = minimize(fun, [0, 0], method="SLSQP", constraints=cons) print(res.x)注意这里fun写成x[0] + x[1] - 1 >= 0的形式,对应讲义里g(x) >= 0的标准写法。SLSQP 本质上就是序列二次规划思想的实现,跟课件里讲的 SQP 是一路思路。把解析求解的 KKT 候选点和数值解对比,误差在 1e-6 量级说明你对条件本身的理解是对的。
4.4 线性规划与单纯形法:手写推导和程序实现对不上的时候
线性规划部分通常会有大段单纯形表的手推演示,换个问题带进去算,流程本身就是算法。这部分的坑在于:手推的时候你可能把“最小化”问题改写成“最大化”问题,符号一多就容易错。建议先用课件里最原始的例子手算出答案,再用scipy.optimize.linprog验证一遍。课件里如果给的是最大化问题,linprog 默认做最小化,目标函数系数要取负号:
from scipy.optimize import linprog c = [-1, -2] # 想最大化 x1 + 2x2 A_ub = [[1, 1], [2, 1]] b_ub = [4, 6] res = linprog(c, A_ub=A_ub, b_ub=b_ub, method="highs") print(res.x)method="highs"是 scipy 现在推荐的内点法实现,它跟讲义里单纯形法收敛到的最优解应该一致,但迭代路径完全不同。如果你手推的结果和linprog对不上,先检查约束方向是<=还是>=,再检查目标函数正负号,这两个位置是出错率最高的。
4.5 做一张一页纸公式表:把散装章节串成闭环
整理完前面几块,最后做一个可以贴墙上的公式表,格式不用复杂,能让自己五分钟找回一个主题的关键点就行。
| 主题 | 核心内容 | 验证方式 |
|---|---|---|
| 无约束优化 | 梯度、Hessian、步长、拟牛顿 | 自己实现梯度下降并与 scipy BFGS 对比 |
| 约束优化 | 拉格朗日函数、KKT、罚函数 | 解析求解 KKT 候选点并与 SLSQP 数值解对比 |
| 线性规划 | 单纯形表、对偶理论、内点法 | 手推单纯形表并用 linprog 验证 |
| 凸优化 | 凸集、凸函数判定、凸规划性质 | 能判断讲义中的例子是否为凸问题 |
这张表不要追求把所有公式列全,只列你当时看不懂、后来又费劲查过的内容。它存在的意义是把课件按主题而不是按文件顺序串起来。资料是死的,知识主线是活的,公式表就是主线的节点。
5. 课程资料包的翻车点和排查:解压、编码、代码版本三块硬骨头
5.1 CRC 错误:不是包坏了,先测完整性再看磁盘
现象:7z x解压到一半,屏幕刷出一行CRC Failed,然后解压中断,你下意识觉得这个包废了。
原因:大概率不是包本身坏了,而是文件在下载或拷贝过程中出过差错。U 盘拷贝中断、下载工具多线程写文件出错、分卷文件没下全,都会让包内某个数据块 CRC 校验失败。少部分情况是内存不稳定导致解压过程中的临时数据出错,这属于玄学范畴,遇到的概率很低但确实存在。
解决:先跑7z t 北航最优化理论与方法.7z做完整测试。如果测试报告某个文件 CRC 错误,优先重新获取压缩包,而不是反复原目录解压。如果你拿到的是分卷包,确认所有分卷都在同一个目录且文件名完整;然后不要把包放在 U 盘里直接解压,先复制到本地磁盘再操作,U 盘的读写稳定性坑过不少人。
5.2 解压后文件名乱码:先确认语言环境,别急着改名
现象:解压完发现文件名是鏁版暟瀛之类的乱码,或者干脆显示成一串问号,文件内容打开却是正常的。
原因:7z 格式内部文件名虽然以 Unicode 记录,但如果打包方在 Windows 上用旧版工具并且用了非 Unicode 方式记录文件名,解压到 UTF-8 环境的 Linux 上就会错位。Windows 端用 Bandizip 这类工具解压,乱码概率会低很多,因为它在解压时会自动识别 GBK 编码并转换到系统当前代码页。
解决:先在终端执行locale,确认LANG是zh_CN.UTF-8。如果显示POSIX或C,把终端切到 UTF-8 再重新解压一次。Linux 下文件名乱码不是元数据损坏,只是显示层面和存储编码不匹配,文件内容不会受影响。数量少就手动重命名,数量大再考虑用批量重命名工具逐个规则替换,不要直接写脚本无脑改,容易把原本正常的文件名也带歪。
5.3 MATLAB 代码跑不动:先看工具箱,再考虑 Octave 或 scipy
现象:2_代码/里的.m文件用 MATLAB 打开,运行到某一行报错:Undefined function or variable 'fmincon'。
原因:课件里的代码依赖 Optimization Toolbox,而你的 MATLAB 没装这个工具箱,或者版本太老。更常见的是你用的根本不是 MATLAB,而是想用 Octave 打开,Octave 对 7z 解压出来的代码文件支持不完整,尤其是fmincon、quadprog这类工具箱函数。
解决:先grep一下代码里到底用了哪些工具箱函数,把依赖清单列出来。常用的对应关系可以参考下面这个表:
| MATLAB 函数 | 用途 | Python 替代 |
|---|---|---|
fmincon | 约束非线性最小化 | scipy.optimize.minimize(method="SLSQP") |
linprog | 线性规划 | scipy.optimize.linprog(method="highs") |
quadprog | 二次规划 | scipy.optimize.minimize(method="trust-constr") |
这个对应只是接口层面的,数值行为需要拿具体问题验证。如果课件里明确要求用 MATLAB,那该装工具箱就装;如果只是想跑通结果验证思路,转成 scipy 是更快的路径。
5.4 复现不出讲义里的结果:初值和步长才是最大玄学
现象:代码运行成功,但输出的最优解跟讲义上印刷的结果对不上,误差大得离谱。
原因:最优化算法对初始点、终止容差和步长极其敏感。讲义上给出的一组结果,往往是在特定初值、特定容差下得到的,你换一个初值,迭代路径完全变化,最终收敛点可能一样,但迭代步数差十几倍。还有一些方法如梯度下降,对步长大到一定程度直接发散,发散时输出的“最优解”自然是错的。
解决:先把代码里的初始点改成和讲义完全一致,再看终止条件。scipy 里options中的tol默认值跟 MATLAB 的TolFun默认值不同,差一个数量级结果都可能不一样。如果整改完还是不对,别改代码硬凑答案,回到算法本身检查你的梯度公式是不是写错了——这个位置永远是最容易出错的地方。
5.5 加密分卷包:没有密码就别花时间猜
现象:解压时弹出输入密码对话框,输入几次都不对,于是开始在网上搜“压缩包密码怎么破解”。
原因:打包方设了密码,可能是课程资料在分发时做了访问限制,也可能是压缩工具默认勾选了加密。
解决:先看包内和包外有没有 README 或说明文件,很多课程资料的密码就写在课程通知或文件名末尾。如果找不到密码,直接联系发资料的人要,这是成本最低的路径。猜密码是性价比最低的动作,暴力枚举加密的 7z 包在时间上没有实际意义。这门课的资料外边可能有多个副本,换一个明确的来源通常比跟一个加密包死磕快得多。
6. 把讲义里的算法亲手实现一遍:最值得投入的验证方式
看再多的 PPT 都不如亲手跑通一个算法。这里给一个很实用的验证技巧:先用 scipy 自带的梯度检查函数验证你手写的梯度公式,再跑优化。很多算法“翻车”的本质不是优化方法不行,而是梯度从第一步就写错了。
import numpy as np from scipy.optimize import check_grad, rosen def my_grad(x): dx0 = -400 * x[0] * (x[1] - x[0] ** 2) - 2 * (1 - x[0]) dx1 = 200 * (x[1] - x[0] ** 2) return np.array([dx0, dx1]) err = check_grad(rosen, my_grad, np.array([1.2, 1.0])) print(err)check_grad会拿你的解析梯度跟数值差分计算的梯度做对比,返回误差。误差在 1e-8 以下说明梯度公式写对了,这时候再去跑优化算法,结果才值得相信。我自己的习惯是:每读完课件里一个算法,就挑一个最简单的例子,不带任何求解器、不调现成库,纯手写一遍迭代过程,然后拿 scipy 的结果当裁判对答案。对上了,说明这个算法的更新公式真懂了;对不上,回头翻课件,从头检查是步长逻辑错了还是矩阵更新方向反了。
这个习惯帮我省掉了无数次“看起来懂了,一写就废”的尴尬。以前我也干过把压缩包里的 PDF 一口气全看完的事,结果一周后脑子里只剩“梯度下降”四个字。后来改成读一章写一段代码,跑通才算数,才真正把这门课变成自己能用的东西。希望帮到你。
本文还有配套的精品资源,点击获取