写技术笔记时,公式最难维护的部分往往不是某个希腊字母,而是:推导换行以后等号能否对齐,插入一个公式以后正文引用会不会过期,参考文献增加以后编号能否自动更新。本篇用一个最小二乘问题,把这些工作连成一套可以实际练习的写作方法。
学习前先完成文档结构与中文编译。完整路线、项目入口和编译环境见学习指南,后续的图表内容见图片、表格与长文档。所有内容集中在独立的 LaTeX 分类。
配套材料:下载完整练习工程 · 查看编译后的 PDF。工程将导言区、数学章节、图表章节和 references.bib分开保存;本文的短代码用于逐项理解,完整工程用于一起练习。
一、先固定符号约定和宏包
本文约定小写斜体表示标量,粗斜体表示向量或矩阵,正体下标表示文字说明。它是一套便于练习的约定;写论文时应优先遵守所用模板和学科规范。符号一旦选定,就不要在同一篇文章里让 x、\mathbf{x}、\bm{x}轮流表示同一个向量。
导言区先加入:
\usepackage{amsmath,amssymb,bm} |
amsmath提供公式环境、文本嵌入和运算符声明;amssymb扩展数学符号;bm提供数学对象的加粗命令,包含希腊字母;amsthm处理定理和证明。它们各有职责,不需要为了“公式更专业”再一次性加载十几个宏包。AMS 数学宏包说明、bm 宏包说明和amsthm 宏包说明可以用来查各自边界。
自己定义 \vect 有一个实际好处:以后需要把向量改为带箭头的样式,可以集中修改定义。宏的名字应表达含义;不建议为了少敲几个字符,把 \section 改成难以理解的单字母命令。
这里使用传统数学字体配置。若以后采用 unicode-math 和 OpenType 数学字体,应重新确认粗体命令和符号配置,不要原样叠加两套字体方案。
二、先区分行内、行间和编号
短表达式是句子的一部分,例如“当 时继续检查矩阵的秩”。较长的目标函数应独立成行。下面是同一个概念在 .tex 文件中的两种写法:
设 \(\vect{x}\in\R^n\),\(\vect{A}\in\R^{m\times n}\), |
显示效果:
注意范数下标里的 2 表示二范数,右上角的 2 表示平方,两者不可互相替代。\frac{1}{2} 是排版命令,也不会自动检查目标函数是否符合你要描述的模型。
需要在下文引用时,改用带编号的环境:
\begin{equation} |
\eqref自动带括号;\ref只输出编号。~是不换行空格,用来避免“式”和编号分到两行。标签名表示内容,例如 eq:least-squares,不要写成 eq:3,因为第三个公式随时可能变成第四个。
| 要表达的结构 | 使用方式 | 编号行为 |
|---|---|---|
| 句子里的短表达式 | \(...\),也可使用 $...$ |
不编号 |
| 独立的一条公式 | \[...\] 或 equation* |
不编号 |
| 一条可引用的公式 | equation |
一个编号 |
| 多条需要对齐的公式 | align |
默认每行一个编号 |
| 一个公式内部的多行结构 | equation 包住 aligned |
整体一个编号 |
| 分段定义 | 数学环境内使用 cases |
由外层决定 |
在 .tex 文档中不要以 $$...$$作为行间公式的常规写法,使用 LaTeX 环境更容易与编号、间距和宏包配合。本网站的 Markdown 数学渲染器使用美元分隔符,网页写法和 .tex 源文件写法应分别理解;复制上方标明 latex 的代码即可。
三、对齐是在描述结构
多条公式:align
设矩阵与向量都是实数,且维度与上一节一致,则最小二乘目标函数的梯度和 Hessian 为:
\begin{align} |
每个 &标记对齐位置,这里放在等号前;\\结束当前行。不要用若干空格把等号推到一起,数学模式里的普通空格不会承担这种布局职责。align已经是行间数学环境,外面不要再包一层 \[...\] 或 equation。
如果中间行不需要编号,在该行加 \notag;如果整组都不需要编号,使用 align*。准备引用的行必须保留编号,并把 \label放在该行中、换行命令之前。amsmath 使用手册的 displayed equations 部分说明了这些环境的差别。
一条推导分成多行:equation 加 aligned
\begin{equation} |
外层表示一个带编号的公式,内层负责两个等号的对齐。aligned本身不负责开启数学模式;它也可以放在 \[...\]中,得到不编号的多行结构。长公式最好在等号、加号或乘积结构边界处拆开,不要先缩小字体,也不要把整页文字宽度改大来容纳一个局部问题。
分段函数:cases
下面的 Huber 损失中,阈值 。两段在边界处的值应相等,这个数学条件需要作者自己确认。
\begin{equation} |
cases中的 &分开“取值”和“条件”,\\分开各个分支。这里只用 \dfrac让分数容易阅读;在行内表达式里强行使用大分数,可能撑高行距。
四、字形要告诉读者“这是什么”
数学模式默认把字母当作变量。直接写 sin(x) 会把 s、i、n当成连续变量;应写 \sin x。同样,直接写 rank(A) 不如定义并使用 \rank(\vect{A})。
| 目的 | 示例 | 含义 |
|---|---|---|
| 已有函数 | \sin\theta、\log x |
使用定义好的运算符及其间距 |
| 临时运算符 | \operatorname{diag}(1,2,3) |
正体运算符名称 |
| 重复使用的运算符 | \DeclareMathOperator{\rank}{rank} |
在导言区统一声明 |
| 带下方约束的运算符 | \DeclareMathOperator*{\argmin}{arg\,min} |
星号允许行间样式把约束放在下方 |
| 表示说明的下标 | x_{\mathrm{ref}} |
ref是一项说明,不是三个变量的乘积 |
| 公式内的短语 | \text{subject to} |
按文本处理,保留单词之间的空格 |
| 粗体希腊符号 | \bm{\theta} |
表示约定中的向量参数 |
\mathrm适合简短的正体数学标记,不适合拿来排一整句自然语言;说明语句使用 \text。运算符需要的不只是正体字形,还有左右间距,因此不要把 \mathrm{rank}当作所有运算符声明的替代品。
量值和单位也要分清。例如 \(t=2\,\mathrm{s}\)中,t是变量,s是秒,\,提供一个小间隔。大量含单位的数据请统一使用 siunitx,对应写法与表格对齐见图表篇。微分记号可按本文约定写为 \mathrm{d}t;不同出版规范可能采用不同字形,要先统一约定再应用。
五、矩阵和定理也有结构
另一种常见向量约定是箭头记号:\vec{v} 适合单字母,\overrightarrow{AB} 适合从点 A 到点 B 的方向。它们与本篇的粗体约定都是排版选择;一份文档中选定一种约定后保持一致。可以修改 \vect 的定义来统一切换,而不用逐条改公式。
矩阵与维度检查
\[ |
bmatrix自带方括号,pmatrix自带圆括号;不带括号时可用 matrix。矩阵里 &分列,\\分行。上述矩阵是三行两列,参数向量是两行一列,所以乘积是三行一列,能与观测向量比较。
LaTeX 不会替你检查矩阵乘法是否合法。即使把参数向量多加一个元素,它也可能正常生成 PDF;因此每次引入矩阵,先在正文说明维度,再检查乘积、转置和逆矩阵是否存在。需要括号自动伸缩时可用成对的 \left、\right,但不要跨 align 的换行符配对;分行时分别选择合适大小的括号更清楚。
定理与证明
在加载 amsthm之后声明环境;如果还使用下一节的 cleveref,把环境声明放在该宏包加载之后:
% 导言区 |
[section]让定理编号与节关联;proof提供证明结构和结束标记。如果把“正定”改成“半正定”,唯一性结论就不再普遍成立,排版系统仍然不会报错。这正是“数学正确”和“排版正确”需要分开验收的原因。
六、交叉引用与超链接
在本文使用的宏包组合中,先加载数学、图表和文献宏包,再加载 hyperref,最后加载 cleveref。hyperref使引用可点击,cleveref按被引用对象的类型添加名称。后者对加载顺序有要求,不能把“hyperref 最后加载”当成没有例外的口诀。见 hyperref 文档和 cleveref 手册的宏包交互说明。
\usepackage[hidelinks]{hyperref} |
正文可写 \cref{eq:gradient,eq:hessian},把名称和多个编号交给宏包处理。中文名称需要像上面这样明确配置;不能假设英文默认设置会自动变成中文。不要在 \cref之前再手写一个“式”,否则可能重复。
把 \label放在产生目标编号的位置:章节的 \section之后,图表的 \caption之后,公式环境或相应公式行内部。不要把图的标签放在 \caption之前,再指望它一定得到该图编号。
交叉引用至少经历“记录标签”和“读取标签”两个阶段,因此首次编译出现 ??并不罕见。但完整构建结束后仍然存在 ??,就应检查标签拼写、重复标签、位置和构建日志,不能把问号当成正常结果交付。也不要手写“见公式 (7)”或用 \tag{7}掩盖引用问题;\tag用于确实需要指定特殊标记的场景,不承担自动编号管理。
七、参考文献:只建立一条完整链路
本文选定 BibLaTeX + Biber:.bib保存文献数据,BibLaTeX 控制引用和文献表样式,Biber 处理数据。这样可以把“引用哪篇文献”和“使用什么编号样式”分开管理。BibLaTeX 官方说明介绍了这种职责划分。
1. 建立 references.bib
新建 UTF-8 文件 references.bib:
@book{knuth1984texbook, |
条目中的书名、年份、出版社和 ISBN 对应 Knuth 本人的书目信息。参考文献练习也要使用能追溯的真实条目,不要随手编造 DOI 或页码。
knuth1984texbook是引用键,不会因为书在文献表里排第几而变化。作者用“姓, 名”便于解析;多名作者用 and分隔,不要用逗号连接整个作者列表。书名中内层的 {TeXbook}保护这一部分的大小写。代码围栏标为 bibtex只是语法高亮名称,不代表本例要运行 BibTeX 程序。
2. 写一份最小 main.tex
下面的完整例子可单独用于排查文献环境,不依赖本篇其它数学代码:
\documentclass[UTF8,fontset=fandol]{ctexart} |
numeric采用数字引用,sorting=none让文献表按引用顺序排列。默认只列出实际引用的条目;把一百条资料放入 .bib,并不意味着它们都应该出现在文末。\nocite{*}可以列出全部条目,但练习时不应靠它掩盖正文漏引。字段和命令的详细定义见 BibLaTeX 用户手册。
这套配置不要再混入旧模板的 \bibliographystyle、\bibliography或另一个 natbib加载语句。以后遇到期刊强制的旧模板,应按该模板单独建立构建方案,而不是把两套链路拼到同一份文档里。
3. 让 latexmk 驱动构建
在同时包含 main.tex与 references.bib的目录执行:
latexmk -xelatex -interaction=nonstopmode -halt-on-error main.tex |
latexmk会根据依赖和辅助文件判断何时调用 XeLaTeX、何时运行 Biber,以及是否需要再次编译。它需要环境中已经提供相应程序,不会替你凭空安装缺失的 Biber。自动构建的职责见 latexmk 文档。
为理解中间过程,可以在这个简单例子中手动执行:
xelatex -interaction=nonstopmode -halt-on-error main.tex |
第一步让文档写出 Biber 所需的 .bcf等信息;Biber 读取文献数据库并生成 .bbl;后续编译读入结果,继续稳定引用编号。这里的 biber main对应文档任务名,参数不是 references.bib。平时用 latexmk判断是否完成,不必机械地背诵“永远编译四次”。
本仓库提供统一的 Docker 练习环境。在仓库根目录执行:
./bin/site.sh latex-build |
构建项目、输出位置及已有目录保护规则见学习指南。可以传入新的输出目录保留一次独立结果,例如 ./bin/site.sh latex-test build/latex-practice-02。这些命令用于本仓库的完整练习项目;上面的两文件例子用于理解最小依赖。
八、从现象定位问题
| 现象 | 先检查什么 | 为什么 |
|---|---|---|
Missing $ inserted |
数学命令是否落在正文,正文下划线是否转义 | TeX 发现需要数学模式的内容 |
Misplaced alignment tab character & |
&是否写在对齐环境之外 |
普通正文中的符号应写 \& |
Undefined control sequence |
宏包是否加载、命令是否拼错 | 后续报错可能只是第一次错误的连锁结果 |
| 公式越过右边界 | 看日志中的 Overfull \hbox,拆分长表达式 |
成功生成 PDF 不等于布局合格 |
公式编号显示 ?? |
标签名、标签位置、重复标签、是否完成重编译 | 引用数据还未生成或没有正确读取 |
| 引文显示引用键或未定义引用 | .bib路径和引用键、Biber 是否执行 |
文献处理链路尚未闭合 |
Please (re)run Biber |
查看 .blg、确认使用 Biber 后端 |
只反复执行 XeLaTeX 不能替代文献处理 |
| Biber 报数据版本不兼容 | BibLaTeX 与 Biber 是否来自兼容的发行环境 | 混用系统包和手工更新可能造成版本不匹配 |
| 文献表为空 | 有无 \cite和 \printbibliography |
导入数据库与输出文献表是不同操作 |
排查时先看 .log中的第一条实质错误,再看 Biber 的 .blg。只对自己能够解释的辅助文件执行清理;不要靠删除全部文件碰运气,更不要误删 .tex、.bib和原始图片。若更改过后端或大幅调整构建配置,可在保留源文件的前提下清理派生文件,再做完整构建。
九、做三次会暴露问题的练习
练习 A:让编号自动改变。 在 eq:gradient之前插入一条新的带编号公式,再构建。检查正文引用是否自动更新、PDF 链接是否跳到正确位置。验收时要同时检查编号文本和点击目标;只看编号“像是对的”还不够。
练习 B:让数学条件发生变化。 把定理中的正定改为半正定,构造 diag(1,0)的例子。确认 LaTeX 仍会编译,但最小点不再唯一。然后修正定理表述。把这次练习记录为“排版检查通过,数学检查未通过”,养成分开判断的习惯。
练习 C:故意破坏一条引用。 将正文的 knuth1984texbook改成不存在的键,完整构建并寻找 warning;记录 PDF 与日志的表现,然后恢复。再添加一条来自真实出版社或作者主页的文献,先核对元数据,后添加引用。验收标准是没有未定义引用、文献表信息可追溯、正文顺序改变后编号仍正确。
完成后应当能回答:为什么 aligned需要外层数学环境?为什么 \operatorname与 \mathrm不能随意互换?为什么插入公式不该手改十处数字?为什么 .bib已经存在,仍然可能没有参考文献?把答案连同你编译出的 PDF 留在自己的练习记录里,再继续图表与长文档篇。