开始学习之前 独立编写的有限自动机、文法、可计算性与逻辑指南。每个主题提供原创完整例题、定义、推理检查与教学补充。
开始前需要了解 初步了解集合、函数与反证法;正文会解释关键术语 能够阅读简单 Python 条件、循环与递归 愿意跟随有限图与逐步符号说明 你将学到什么 构造并比较正则表达式、确定与非确定有限自动机 设计文法,跟踪 Chomsky 范式转换与 CYK 解析 区分可判定性、可识别性与计算效率 用真值赋值和量词检查形式主张 把知识连接起来 按阶段循序渐进。也可以点击任一主题,阅读故事、方法与例子。
COMP2022 / 01 Leon
字符串、语言与规格 01 / 从一个故事开始 想象门卫检查标签。选择扫描器前,先规定允许哪些标签,例如由 A、B 组成且以 B 结尾的序列。规格独立于检查设备描述规则。设备可以使用指示灯、程序或查表;不同实现仍能作出相同判断。类比也有限制:真实扫描器会机械故障,数学机器却严格遵守规则。我们研究规则是否描述了预期标签集合。
02 / 理解原理 字母表是有限符号集合,字符串是由这些符号组成的有限序列。空串 ε 长度为零。语言是所有有限串的任意子集,不一定是人类语言,也不一定能用实用方法描述。判定问题可表示成语言成员资格:答案为是的输入属于语言。
规格说明输入范围和要求答案,算法提供步骤。实现只有对每个允许输入都符合规格才正确。一般计算还需说明是否要求终止:只要结束就答对,比总能给出答案弱。
先认识这些词
字母表 允许符号构成的有限集合。
字符串 有限的有序符号序列。
规格 说明允许输入与所需输出的规则。 04 / 先看一个完整例子 设 Σ={A,B},L 为以 B 结尾的串。B、AB、BAB 属于它,ε、A、BAA 不属于。正确过程先拒绝空输入,再检查最后符号是否为 B。若表示方式允许,可以直接查看末字符;也可以从左到右扫描并记住最近字符,两者符合相同规格。只检查有没有 B 的过程在 BAA 上失败,这是具体反例。
一步步想清楚 为什么将规则与扫描器分开? 不同过程可符合相同规则,需要用统一目标判断。
{x,y} 上有几个长度二的串? 两个位置各两种选择,2×2=4:xx、xy、yx、yy。
{ε} 是空集合吗? 不是。它包含一个长度零的串。
完整推导一道题 · 01 统计有限部分 在 Σ={x,y} 上列出长度不超过二且以 x 结尾的全部串。候选输入包括 ε,但必须严格检查结尾规则。
先选择方法 按长度划分,避免漏计与重复。
长度零只有 ε,没有末尾 x,因此拒绝。
长度一有 x、y,只有 x 以 x 结尾。
长度二有 xx、xy、yx、yy,检查第二位保留 xx、yx。
解释最终答案 所选有限部分为 {x,xx,yx},共三个串。
检验推理 正长度 n 时,固定末尾 x 后有 2^(n−1) 种。n=1、2 得 1+2=3。
完整推导一道题 · 02 修复错误检查 规则为“二进制输入恰含两个 1”。候选测试在长度为二时接受。检查 10、101,并给出会停机的正确过程。
先选择方法 将候选条件与真实计数比较,再替换条件。
10 长度二,候选接受;但只有一个 1,要求答案为否。
101 长度三,候选拒绝;但有两个 1,要求答案为是。
扫描有限输入,遇 1 加一。读完后仅在计数等于二时接受。
解释最终答案 仅看长度既会误接受也会误拒绝。计数过程在读完输入后停机。
Leon 的进一步思考 先检查输入合法性 字母表为 {x,y} 时,xz 不在输入范围。实现应说明报输入错误还是答否,不能悄悄改变数学语言。
反例有决定作用 一次不符就足以推翻对所有输入正确的主张。一千次成功测试也不能覆盖无限输入。
注意这个边界. 不要混淆 ε 与 ∅。ε 是一个串,∅ 没有任何串;{ε} 有一个成员。
检查自己的理解: 所有二进制串的集合是一个字符串吗? 不是。它是无限语言 {0,1}*。每个成员都有限,但成员数量无限。
↑ 返回知识框架 COMP2022 / 02 Leon
正则表达式:语言的代数 01 / 从一个故事开始 玩具制作有三种指令:选一种设计、将两块并排、把一块重复有限次。正则表达式也像字符串配方。选择给出替代项,连接拼起片段,重复允许数量变化。配方描述所有成品,不规定制作先后。重复可以为零次,容易遗漏。数学配方也不包含某些程序库的强大扩展,因此讨论正则语言时须明确基本运算。
02 / 理解原理 正则表达式从符号、空语言、空串、并、连接和 Kleene 星递归构造。语义给每个表达式对应语言。并允许来自任一边的串;连接要求串可拆成左语言的片段与右语言的片段;星允许零个或多个成员连接。
括号决定分组。通常星优先于连接,连接优先于并。本课匹配指整个字符串的成员资格;子串搜索是另一任务,除非表达式允许任意前后文。表达式是规格,不是对回溯实现的承诺。
先认识这些词
并 接受任一选择的字符串。
连接 把一个串接在另一个后面。
Kleene 星 将语言成员连接零次或多次。 04 / 先看一个完整例子 R=(ab|c)*d 的重复块是 ab 或 c,末尾恰有一个 d。选 ab、c、ab 得 abcabd,匹配。零块得 d,也匹配。acd 不匹配,因为末尾 d 前的 ac 无法分成 ab 或 c:a 后缺少 b。dcc 不匹配,因为 d 必须在末尾。写出分块就能解释成员资格。
一步步想清楚 零次重复为何重要? 即使重复块非空,也会加入 ε。
xyx 如何按 (xy|x)* 分块? 选择 xy 后接 x,因此属于该语言。
前缀匹配能证明整体匹配吗? 不能,剩余每个符号也必须由表达式匹配。
完整推导一道题 · 01 分解新模式 对 R=(xy|z)*x,判断 xyzzx、x、zxy 的成员资格,要求整个串匹配。
先选择方法 先分离必须的末尾 x,再拆重复前缀。
xyzzx 以 x 结尾,前缀 xyzz 可拆成 xy、z、z,均允许。
x 留下空前缀,星允许零个重复块。
zxy 以 y 结尾,无论前面怎样分块都不能提供末尾 x。
解释最终答案 xyzzx、x 匹配,zxy 不匹配。
检验推理 若删除模式末尾 x,语言会改变,ε 将匹配。
完整推导一道题 · 02 比较星的位置 在 {a,b} 上各找一串:属于 a*b* 不属于 (ab)*,以及相反。
先选择方法 比较块顺序:分组连续段与交替配对。
aab 是两个 a 后接一个 b,因此属于 a*b*。
非空 (ab)* 交替 a、b 且长度为偶数。aab 长三,因此不属于。
abab 是两个 ab 块,但第一个 b 后又有 a,违反先全 a 后全 b 的结构。
解释最终答案 aab 见证第一方向差异,abab 见证反方向。两语言互不包含。
检验推理 两者都接受 ε,因此共享空串不能证明等价。
Leon 的进一步思考 表达式与实现 表达式说明哪些串属于语言。回溯与同时状态模拟执行不同,却可以所有答案一致。
星不等于加 一次或多次可写 RR*。当 R 本身不能生成 ε 时,它与星的区别就是是否包含 ε。
注意这个边界. R* 总包含零次重复带来的 ε,即使 R 本身什么也不匹配。
检查自己的理解: a*b 与 (ab)* 有什么不同? a*b 是任意数量 a 后接一个 b。(ab)* 重复完整 ab 块,也含 ε。aab 只属于前者。
↑ 返回知识框架 COMP2022 / 03 Leon
DFA 状态:概括已经读过的内容 01 / 从一个故事开始 门口计数器只需两盏灯报告进入人数奇偶,不必保留每次到达时间。每来一人切换灯,当前灯概括最终奇偶问题所需全部信息。确定有限自动机也如此:状态代表已读前缀的信息摘要。设计应先命名每个状态含义。若任务要求无限制精确计数,类比就到头了,因为固定灯数不能记住任意多种总数。
02 / 理解原理 DFA 有有限状态集、输入字母表、起点、接受状态集及完整转移函数。每次转移恰读一个符号,因此每个输入有唯一运行过程,读完全部输入后按最终状态判断接受。
围绕不变量设计状态:读完前缀后,当前状态保证什么?奇偶只需偶与奇;固定子串可记录最长有用后缀。定义必须包含每个状态与符号组合,包括拒绝汇点。先证初始不变量,再证每步保持,最后连接接受状态与规格。
先认识这些词
状态 已处理前缀的有限摘要。
不变量 每次转移后保持的陈述。
接受状态 输入结束于此时接受的状态。 04 / 先看一个完整例子 识别含奇数个 1 的二进制串。用 E、O 两状态,从 E 开始,只接受 O。读 0 不变,读 1 在 E、O 间切换。10110 的序列为 E,O,O,E,O,O,因此接受。ε 留在 E,因此拒绝。不变量为 E 表示已读前缀含偶数个 1,O 表示奇数。它能证明所有串,不只是例子。
一步步想清楚 余数计数为何只需少量状态? 问题不需要完整总数,只需要余数。
模三余数二再读一个 1 会怎样? 2+1=3 余零,转到零状态。
接受前缀保证延长后也接受吗? 不保证,额外符号可改变所概括性质。
完整推导一道题 · 01 跟踪余数机 状态 0、1、2 表示 1 的个数模三。从 0 开始,只接受 0;读 0 不变,读 1 加一模三。跟踪 110101。
先选择方法 每读一符号记录状态,并以累计个数核对不变量。
初始计数零、状态 0。前两个 1 得计数 1、2,状态 1、2。
下一 0 保持状态 2,下一 1 让计数到三,状态回 0。
倒数第二个 0 保持状态 0,最后 1 让计数到四,结束于状态 1。
解释最终答案 完整轨迹 0,1,2,2,0,0,1。四不能被三整除,因此拒绝。
检验推理 直接数到四个 1,4 mod 3=1,与末状态一致。
完整推导一道题 · 02 设计末符号机器 在 {a,b} 上设计完整双状态 DFA,接受非空且以 b 结尾的串。
先选择方法 只记最近符号是否 b,把空前缀与拒绝状态归为一组。
状态 N 表示空或末符号 a,B 表示末符号 b,从 N 开始。
任一状态读 a 到 N,读 b 到 B,完整定义四种状态符号对。
输入结束只接受 B。bab 的状态 N,B,N,B;ε 保持 N。
解释最终答案 该完整 DFA 接受 bab、拒绝 ε,符合末符号规则。
检验推理 在任何接受串后加 a 都转 N,因为所要求末字符已改变。
Leon 的进一步思考 证明状态含义 余数机初始计数零;0 保持计数,1 同时增加计数与余数。这两种情形证明所有转移,不只一次运行。
表示是设计选择 若问末符号是否 1,奇偶状态不足:10 与 1 奇偶相同,末符号不同。摘要必须匹配实际问题。
注意这个边界. 不能一到接受状态就接受,后续符号可能离开它,必须消费全部输入。
检查自己的理解: 识别 1 的个数能被三整除的二进制串需要多少状态? 三个,表示计数除以三的余数。读 1 推进余数,读 0 不变,仅余数零接受。
↑ 返回知识框架 COMP2022 / 04 Leon
非确定性与 ε 转移 01 / 从一个故事开始 想象一队人按给定颜色序列探索迷宫。到路口时,他们探索每条兼容分支。只要至少一人读完全部颜色并到达许可房间,任务就成功。失败分支不会取消成功分支。有些无色通道不消耗颜色即可经过,类似 ε 转移。这是推理模型,不是说电脑真有无限探索者;一个有限可达状态集合就能表示全部活跃分支。
02 / 理解原理 NFA 对一个状态与符号可有零个、一个或多个后继。ε 转移改变状态但不读符号。接受要求存在一条有限路径,消费全部输入并停在接受状态。其他分支卡住、结束于非接受状态或在 ε 边循环,都不取消成功路径。
NFA 易于组合:并选择分支,连接把一机器终点连到下一机器,星允许反复通过并提供空输入选项。这解释正则表达式转自动机。非确定性改变描述便利性与大小,却不增加正则语言的范围。
先认识这些词
非确定性 一次转移可能有多个后继状态。
ε 转移 不消费输入符号的状态改变。
存在性接受 一条有限、完整、成功的运行就够。 04 / 先看一个完整例子 识别以 ab 结尾的 {a,b} 串。起点在两字母上自环,也允许读 a 到第二状态;第二状态读 b 到没有出边的终点。baab 上,一分支猜第一个 a 是后缀起点,却被下一个 a 卡住;另一分支等到第二个 a,再读末尾 b 接受。aba 上,一分支在 ab 后到终点却不能消费末 a,所以全串拒绝。
一步步想清楚 为何可以忽略失败分支? 接受要求至少一次成功,不要求每条分支成功。
ε 会消费空格字符吗? 不会。它什么也不消费,实际空格会是普通字母表符号。
提前到终态就够了吗? 只有还能成功消费全部剩余符号才行。
完整推导一道题 · 01 字母前的免费分支 状态 s,p,f,起点 s,仅 f 接受。边为 s—ε→p、s—a→s、p—b→f,无其他边。判断 aab 与 ba。
先选择方法 每个符号前后维护包含所有免费 ε 移动的活跃状态。
初始闭包 {s,p}。每个 a 沿 s 自环再用 ε 补回 p,读 aa 后仍为 {s,p}。
末 b 将 p 移到 f,因此 aab 最后为 {f} 并接受。
对 ba,b 先产生 {f},f 没有 a 出边,读 a 后为 ∅,因此拒绝。
解释最终答案 接受 aab,拒绝 ba。在前缀后到终态并不够。
检验推理 成功串恰为 a*b:任意个 a 后接一个末 b。
完整推导一道题 · 02 为什么交换 NFA 终态失败 NFA 状态 s,f,字母表 {a},起点 s,终态 {f}。仅有 s—a→s 与 s—a→f。交换终态为 {s} 前后比较输入 a。
先选择方法 列出两条完整运行;补语言应反转整体答案,而非各路径独立结果。
原机器输入 a 有终点 s、f 两条运行。终点 f 的路径成功,因此接受。
交换终态后两条运行仍存在,现在终点 s 的路径成功。
两机器均接受 a。真正补机器应因原机器接受而拒绝 a。
解释最终答案 这个 NFA 交换终态不能得到补语言。
检验推理 确定化后 a 对应唯一子集 {s,f},反转该子集接受性才能正确反转答案。
Leon 的进一步思考 同时模拟可能性 每个前缀后记录可达状态集合。相同未读后缀下到同状态的两路径,未来选择相同,可合并。
ε 环的闭包仍有限 闭包搜索标记已访问状态。环 p→q→p 只各加入 p、q 一次,无需永远重复遍历。
注意这个边界. 不能直接交换 NFA 的接受与非接受状态来求补。存在性接受阻止该技巧,须先转完整 DFA。
检查自己的理解: 一条分支接受,另一条在 ε 转移上永远循环,输入接受吗? 接受。只需存在有限接受运行,其他分支不会取消它。
↑ 返回知识框架 COMP2022 / 05 Leon
把 NFA 转为 DFA 01 / 从一个故事开始 控制室用点亮房间的集合代替迷宫探索队。每读一种颜色,就熄灭旧灯,点亮队员现在可能所在的所有房间。给定前缀后,显示屏只有一种配置,虽然探索路径很多。配置就是 DFA 状态。ε 通道要求额外点亮所有免费可达房间。少量房间也有指数多个子集,所以显示配置可能很多,即使实际运行只出现少部分。
02 / 理解原理 子集构造为每个可达 NFA 状态集合建立一个 DFA 状态。先取起点 ε 闭包;读符号时从当前集合取所有该符号转移,再取 ε 闭包。集合与 NFA 接受集相交就接受。可达空子集应保留为拒绝汇点。
不变量为:每读完一个前缀,DFA 状态恰等于 NFA 在允许 ε 移动后所有可达状态。它证明两语言相同。m 个 NFA 状态最多有 2ᵐ 个子集,但通常只生成可达子集,不枚举所有子集。
先认识这些词
子集状态 表示多个可能 NFA 状态的一个 DFA 状态。
ε 闭包 不消费符号可达的所有状态,包含原集合。
汇点 每条转移都回到自身的状态。 04 / 先看一个完整例子 NFA 有 p,q,r,从 p 开始,p 可经 ε 到 q,p 在 a 上自环,q 经 b 到 r,仅 r 接受。初始 DFA 状态 {p,q}。
读 a 时 p 到 p、q 无后继,闭包补回 q,仍为 {p,q}。读 b 仅 q 到 r,产生 {r}。再读任一字母变 ∅。因此 aab 接受,aaba 拒绝,构造直接显出语言 a*b。
一步步想清楚 为何普通转移后还取闭包? NFA 可在读下一符号前继续免费移动。
四个状态有多少子集? 每个状态选或不选,因此 2⁴=16。
所有可能子集都必须建立吗? 不必,可达子集构造省略所有输入都到不了的子集。
完整推导一道题 · 01 构造四个可达子集 NFA 状态 0,1,2,起点 0,终态 2。边为 0—ε→1、1—x→1、1—y→2。字母表 {x,y},缺失移动为空。构造可达 DFA。
先选择方法 从闭包开始,不断探索新子集直到没有新项。
起点 A={0,1}。读 x 到 B={1},读 y 到 C={2}。
B 读 x 自环、读 y 到 C。C 无普通移动,两符号都到 D=∅。
D 在两符号上自环。仅 C 含终态 2,因此仅 C 接受。A,B,C,D 四个子集可达。
解释最终答案 DFA 有四个可达子集状态,识别 x*y。
检验推理 最多 2³=8 个子集。A、B 行为相同,之后可最小化合并为更小等价 DFA。
完整推导一道题 · 02 跨环求闭包 ε 边为 p→q、q→r、r→q;唯一 a 边为 r→f,只有 f 接受。从 p 开始,求初闭包和读 a 后子集。
先选择方法 用已访问集合,有限探索免费移动环。
零次移动先含 p,再由 p 加 q、由 q 加 r。
r 的 ε 边回到已有 q,因此停止,闭包为 {p,q,r}。
读 a 时 p、q 无后继,r 贡献 f。f 无 ε 出边,后继子集 {f}。
解释最终答案 初子集 {p,q,r};输入 a 最终到接受子集 {f}。
检验推理 若漏初闭包,p 无 a 转移,错误模拟就会拒绝 a。
Leon 的进一步思考 闭包包含自身 状态可以用零次 ε 移动留在原地。忘记零步选项会使有效起点消失。
空子集有用途 没有分支幸存后,后续符号无法复活分支。空子集在所有符号上自环,使 DFA 完整。
注意这个边界. 不能忘起点或每次符号后的 ε 闭包,否则可能丢失接受路径。
检查自己的理解: 同时含接受与拒绝 NFA 状态的子集能接受吗? 可以。只要含一个接受状态,至少一条 NFA 分支就成功了。
↑ 返回知识框架 COMP2022 / 06 Leon
从自动机回到表达式 01 / 从一个故事开始 移除交通图上的小车站时,所有进入该站、可能绕本地环若干次、再离开的路线,都须用新直达连接表示。旧直达路线仍作为另一选择。不断重复后只剩起终点,以及描述全部旅行的连接。状态消除用边上的正则表达式做这种压缩。结果可能比原图长很多,不同消除顺序也会给出外观不同但语言相同的表达式。
02 / 理解原理 广义 NFA 用正则表达式标边。添加无入边的新起点与无出边的新终点,用 ε 接旧边界。缺边表示 ∅,平行边用并合并。移除 k 时,为每个幸存 i→j 加入经 k 的选择:进入、循环任意次、离开。
最后只剩新起终点,其边表达式表示原语言。结合表达式转 NFA 与子集构造,可证表达式、NFA、DFA 表达能力相同,但表示大小与执行成本未必相同。
先认识这些词
广义边 以正则表达式标记的边。
消除 移除状态同时保留幸存端点间全部路线。
自环 从状态返回自身的路线。 04 / 先看一个完整例子 设起点 s、中间 k、终点 f,边为 s→k:a、k→k:b、k→f:c、s→f:d。删除 k 后 s→f 为 d|ab*c。abbbc 走 a 进入、三次 b 循环、c 离开。ac 用零次循环,d 用旧直达边。abcabc 不允许,因为到 f 后不能重启。若无直达边,其标签 ∅,结果简化为 ab*c。
一步步想清楚 为何保留旧边? 有些接受路线从不经过被删状态。
缺失自环贡献什么? 其星贡献 ε,表示绕环零次。
表达式更长就表示不同语言吗? 不是,消除顺序可改变长度而不改接受串。
完整推导一道题 · 01 删除有环中间状态 s,k,f 的标签为 s→f:u、s→k:v、k→k:w|x、k→f:y,无其他边。删除 k 并检验 vwxwy。
先选择方法 区分不经 k 与进入、循环、离开 k 的路线。
不经 k 的路线贡献 u,必须保留。
经 k 路线贡献 v(w|x)*y,每次环独立选 w 或 x。
vwxwy 分成入口 v、环 w,x,w、出口 y,顺序均符合。
解释最终答案 结果 u|v(w|x)*y,接受 vwxwy。
检验推理 零环路线 vy 也匹配,u 不进入 k 仍被接受。
完整推导一道题 · 02 区分缺边与免费边 无 s→f 边。s→k:ε、k→f:ab,k 无自环。删除 k,再与 s→k 缺失的变体比较。
先选择方法 缺边代 ∅,存在的免费边代 ε。
第一图代入 ∅|ε(∅)*ab,旧直达选择为空。
因 ∅*={ε},连接 ε、ε、ab 得 ab。
变体入口为 ∅,因此 ∅|∅(∅)*ab=∅,根本无法进入 k。
解释最终答案 免费入口允许恰为 ab 的串,缺失入口不允许任何串。
检验推理 第一图及其表达式都不接受 ε,因为出口仍需 a、b 两符号。
Leon 的进一步思考 一次更新只用一张旧图 所有经 k 路线应使用消除前标签。同一步混入刚更新标签,可能意外引入不期望的重复结构。
空语言消灭连接 若无入口或出口,经该点路线为 ∅。相反,ε 入口或出口不消费符号,却仍允许路线。
注意这个边界. 不能删掉原 i→j 表达式,不经过 k 的路线也必须保留。
检查自己的理解: 被删除状态没有自环会怎样? 循环标签为 ∅,且 ∅*={ε},因此新路线只是进入表达式接离开表达式。
↑ 返回知识框架 COMP2022 / 07 Leon
匹配策略与重复工作 01 / 从一个故事开始 图书管理员把一排相同卡片分成一张或两张的包。若末尾要求无法满足,她可能撤销选择,反复尝试面对相同剩余任务的不同分法。更有条理的方法记录已到达的不同情况并合并等价尝试。这说明短正则表达式在回溯引擎中也可能很慢,尽管有限状态匹配可行。数学语言与引擎搜索策略是两层,都影响性能判断。
02 / 理解原理 成员问题问整个输入是否属于表达式语言。朴素递归或回溯匹配可能探索同一前缀的多种分解,重复等价子问题。Thompson 风格 NFA 模拟维护活跃状态集,逐符号更新并包含 ε 闭包。
大小 m 的表达式可构造状态与边数 O(m) 的 NFA,直接模拟长 n 输入需 O(mn) 时间、O(m) 工作空间。先确定化后,固定 DFA 的常数时间转移可使匹配 O(n),但构造 DFA 可能需指数状态。这些界针对基本正则表达式,不包括反向引用等扩展。
先认识这些词
回溯 撤销选择并尝试其他路径。
活跃集合 当前输入前缀后所有可达状态。
预处理 匹配某个输入前进行的工作。 04 / 先看一个完整例子 对 (a|aa)*b 与 aaaaac,五个 a 可分成一张或两张块,例如 a,a,a,a,a 或 aa,a,aa。因缺末 b,所有选择最后都失败。回溯可能按许多分法重复发现失败。NFA 模拟合并同前缀后到同状态的分支,c 没有续路时拒绝。改为 aaaaab 则匹配。例子展示重复工作,而没有改变语言。
一步步想清楚 短模式为何也慢? 执行可能重复探索最终同样失败的许多分法。
什么信息允许合并尝试? 相同自动机状态与输入位置表示相同剩余任务。
DFA 构造总便宜吗? 不是。子集构造可产生指数状态,即使后续匹配为线性。
完整推导一道题 · 01 统计重复分解 对 (a|aa)*b 和输入 aaaaac,统计五个 a 分成长度一或二块的方式。不把它当作引擎指令总数。
先选择方法 设 F(n) 为分法数,按第一块长一还是二分类。
F(0)=1 表示空分法,F(1)=1 表示一个单块。
n≥2 时 F(n)=F(n−1)+F(n−2),移去首块剩对应长度。因此 F(2)=2、F(3)=3。
继续 F(4)=3+2=5,F(5)=5+3=8。每种分法最后仍遇 c 而非所需 b。
解释最终答案 八种分法都失败。这量化重复选择,不是通用运行时间。
检验推理 将 c 改为 b 会接受,但 a 块仍有八种分法。
完整推导一道题 · 02 区分准备与匹配 假设已构造 DFA 每符号转移一次。三输入长 4、7、9。构造耗 30 个抽象工作单位,每转移一单位。求匹配成本与总成本。
先选择方法 先累加每输入扫描,再仅加一次准备成本。
前两输入分别需四与七次转移,小计 11。
加第三输入九次,匹配成本为 20。
只加一次构造 30,三输入总成本 50。
解释最终答案 匹配成本 20,完整批次 50。线性扫描并未消除准备成本。
检验推理 若每输入都需新 DFA 且构造成本相同,准备为 90,总数 110。
Leon 的进一步思考 统计状态,不统计想象的人 成员判断无需保留同状态多个副本。路径数可增长而集合仍小;统计解析数是不同问题。
合理分摊准备成本 固定 DFA 多次复用可分摊构造成本。每请求换模式时忽略准备工作,会误导比较。
注意这个边界. 某回溯实现耗指数时间,并不证明正则匹配本身必然指数困难。
检查自己的理解: 为什么同前缀后到同状态的两条 NFA 运行可合并? 未来只依赖当前状态与未读后缀,不同历史不再提供成员判断所需信息。
↑ 返回知识框架 COMP2022 / 08 Leon
正则语言的封闭性与判定过程 01 / 从一个故事开始 一个面板同时记录两传感器状态。第一传感器三种模式,第二四种,组合最多十二对。策略可在两者都许可、任一许可或两者不同意时通过。这就是自动机积。接受状态对表达策略,转移结构不变。检查哪些状态对可达,就能判定是否可能发生分歧,为比较不同规格提供有限过程。
02 / 理解原理 正则语言对并、交、补封闭。相同字母表上的完整 DFA 可构造积,每读一符号同时更新两个状态,再按所需布尔运算选择接受对。求补只需交换完整 DFA 的接受与非接受状态。
模拟可判定成员资格,从起点寻找接受状态可判定非空。等价归约为对称差是否为空:若没有可达状态对恰有一个分量接受,两机器就对所有串一致。表达式转 DFA 因此也能判定表达式等价,虽然转换可能指数增长。
先认识这些词
积状态 记录每台机器一个状态的有序对。
对称差 恰属于两个语言之一的串。
可达性 是否有有限路径从起点到某状态。 04 / 先看一个完整例子 A 接受以 1 结尾的串,B 接受含奇数个 1 的串。积起点是(不以1结尾,偶)。输入 10 时 A 先接受后拒绝;B 读 1 到奇、读 0 不变。末状态恰有一侧接受,所以 10 证明语言不同。可达搜索可用前驱链接还原反例。一个反例足够,很多一致样本则不足。
一步步想清楚 一次分歧为何足够? 等价要求每个输入一致,任一反例就推翻它。
三状态与五状态机器的积大小界是多少? 最多 3×5=15 对,部分可能不可达。
完整 DFA 能交换终态求补吗? 能。每输入恰有一个完整运行,反转末状态接受性就反转答案。
为什么测试很多字符串仍弱于搜索乘积图? 有限样例可能漏掉更长的反例。乘积图虽然节点有限,却覆盖任意字符串可能到达的状态对。
完整推导一道题 · 01 求两个小规则的交 在 {0,1} 上,A 接受偶数长度,B 接受末尾 1。给出积的接受规则,检查 101、01。
先选择方法 独立跟踪长度奇偶与末符号,交要求两者都满足。
状态为 (E,N),(E,Y),(O,N),(O,Y),起点 (E,N)。每符号切奇偶,1 设置 Y,0 设置 N。
101 长三且末 1,状态 (O,Y),不满足偶长。
01 长二且末 1,结束于唯一接受对 (E,Y)。
解释最终答案 交语言接受 01、拒绝 101,仅 (E,Y) 为终态。
完整推导一道题 · 02 寻找语言反例 A 接受偶数个 1,B 接受末 0 串且拒绝 ε。在 {0,1} 上找最短分歧,允许 ε。
先选择方法 搜索边前先检查起点对,空串长度零。
对 ε,A 见零个 1,零为偶数,所以接受。
B 因无末符号明确拒绝 ε,起点对已经分歧。
不存在长度小于零的串,因此不可能有更短分歧。
检验推理 0 被两者接受,说明只看非空例子可能漏掉最简单证据。
完整推导一道题 · 03 跟踪 aba 在两个自动机中的状态 比较“包含 ab”和“以 ab 结尾”。两机都从 0 开始,只接受状态 2。使用程序中的转移表。
先选择方法 每读一个字母记录状态对,读完整个单词后比较接受性。
从 (0,0) 出发。读 a 后都到 1,得到 (1,1)。
再读 b 得到 (2,2),前缀 ab 被两者接受。
最后读 a,得到 (2,1),只有“包含 ab”接受。
解释最终答案 aba 属于对称差,因此两个语言不等价。
检验推理 长度小于 3 且含 ab 的字符串只有 ab 本身,它也以 ab 结尾,因此不存在更短反例。
运行一个完整示例 · 01 找到区分两个 DFA 的最短单词 两位同学制作文本过滤器:一个接受任意位置含 ab 的单词,另一个只接受以 ab 结尾的单词。ab 和 aab 的测试都通过,于是他们以为两个过滤器等价。米娜不再猜测试字符串,而是同时运行两个自动机,搜索恰好只有一个接受的状态对。最终找到 aba,直接说明二者为何不同。
Python 3 复制代码 下载源代码 ↓ 长代码行可左右滚动。复制或下载会保留原始代码。
from collections import deque
from itertools import product
def witness ( a , accepting_a , b , accepting_b ):
alphabet = ( "a" , "b" )
start = ( 0 , 0 )
parents = { start : None }
queue = deque ([ start ])
while queue :
pair = queue . popleft ()
x , y = pair
if ( x in accepting_a ) != ( y in accepting_b ):
letters = []
while parents [ pair ] is not None :
previous , letter = parents [ pair ]
letters . append ( letter )
pair = previous
return "" . join ( reversed ( letters ))
for letter in alphabet :
nxt = ( a [ x ][ letter ], b [ y ][ letter ])
if nxt not in parents :
parents [ nxt ] = ( pair , letter )
queue . append ( nxt )
return None
def accepts ( table , word ):
state = 0
for letter in word :
state = table [ state ][ letter ]
return state == 2
contains = [{ "a" : 1 , "b" : 0 }, { "a" : 1 , "b" : 2 }, { "a" : 2 , "b" : 2 }]
ends = [{ "a" : 1 , "b" : 0 }, { "a" : 1 , "b" : 2 }, { "a" : 1 , "b" : 0 }]
word = witness ( contains , { 2 }, ends , { 2 })
assert word == "aba" and witness ( contains , { 2 }, contains , { 2 }) is None
for size in range ( len ( word )):
for letters in product ( "ab" , repeat = size ):
test = "" . join ( letters )
assert accepts ( contains , test ) == accepts ( ends , test )
print ( "shortest witness:" , repr ( word ))
print ( "contains ab:" , accepts ( contains , word ))
print ( "ends in ab:" , accepts ( ends , word ))
在本地运行 python regular-decision-problems-shortest-dfa-counterexample.py 预期输出 shortest witness: 'aba'
contains ab: True
ends in ab: False
按执行顺序理解 乘积状态 (x,y) 记录两个自动机读完同一前缀后的状态。
状态对入队时标记;图中最多有 |Q_A|×|Q_B| 个状态对。
恰好一个分量接受时,将乘积状态视为目标。这是对称差,而非交集。
用父指针恢复字符串。BFS 保证首次找到的反例按符号数最短。
逐步读懂代码 两个语言不同,当且仅当对称差非空:L(A)≠L(B) 等价于存在 w,使 accept_A(w) 与 accept_B(w) 恰好一真一假。完整乘积搜索可以判定给定有限自动机的这一条件。若找不到可达的分歧状态对,任何单词都会到达判断一致的状态对。
状态数分别为 q_A、q_B,字母表大小为 s 时,时间为 O(s×q_A×q_B),存储状态需要 O(q_A×q_B) 空间。自动机必须完整:每个状态对每个字母都有转移。缺失转移应先补到明确的拒绝汇点。
若初始状态就有分歧,返回空字符串也是合法反例。None 才表示不存在反例。这里的小规模穷举检查核实样例中没有更短反例;乘积状态的访问论证解释一般搜索为何终止。本方法比较 DFA,不能用于判定任意程序等价。
Leon 的进一步思考 共同字母表重要 补集相对于 Σ*。改变字母表会改变未见符号的处理,因此应在共同字母表上补全机器。
广度优先找最短证据 每边消费一个符号时,积图广度优先搜索可找最短分歧串。记录入边符号与父状态以还原。
注意这个边界. 不完整 DFA 求补前要加汇点。缺转移所拒绝的输入也须在补机器中接受。
检查自己的理解: 有限搜索怎能证明无限多个串一致? 每个串都在有限积图中产生路径。若无可达分歧状态,就不存在反例串。
↑ 返回知识框架 COMP2022 / 09 Leon
证明有限记忆不够 01 / 从一个故事开始 衣帽间管理员用固定卡片记录进入人数,稍后必须允许恰同数量离开。人数无上限时,两个不同总数迟早共用一张卡。此后相同退出序列会导致相同行为,尽管一者应该通过,另一者应失败。这不是某套卡片设计失败,而是反对所有固定有限卡片系统的论证。关键在无界的精确要求;人数有上限或只问固定模数余数,就改变了问题。
02 / 理解原理 证明非正则,可说明任何有限状态摘要都保不住所需后缀区别。对 L={aⁿbⁿ:n≥0},假设存在 m 状态 DFA。m+1 个前缀 ε,a,…,aᵐ 中必有 aⁱ、aʲ 到同状态。接同后缀 bⁱ 后两串行为相同,但 aⁱbⁱ 属于 L,aʲbⁱ 不属于,矛盾。
另一技巧利用封闭性:若假设语言正则,与已知正则语言运算后得到已知非正则语言,假设就错。这些论证只排除有限自动机,不表示语言不可判定。
先认识这些词
抽屉原理 对象多于类别时,至少两对象进入同类。
区分后缀 同一追加串使所需成员答案不同。
非正则 没有有限自动机能识别该语言。 04 / 先看一个完整例子 E 为任意顺序下 a、b 数相同的串。若 E 正则,与正则 a*b* 的交也应正则。该交恰为 {aⁿbⁿ:n≥0},重复状态论证已证它非正则,矛盾,所以 E 也非正则。abba 在 E 却不在 a*b*;取交故意排除混合顺序,显出已知困难模式。
一步步想清楚 为什么用 m+1 个前缀? 只有 m 个状态,因此两个前缀必共享一个。
为何恰接 bⁱ? 它配平较短 a 前缀,却不能配平较长者。
非正则是否表示没有算法能判定? 不是。可用无界工作记忆的机器能对有限输入计数比较。
完整推导一道题 · 01 走完必然碰撞论证 假设识别 {aⁿbⁿ:n≥0} 的 DFA 在 a²、a⁵ 后到同状态,解释为何矛盾。
先选择方法 找一个共同后缀,让一前缀必须接受,另一必须拒绝。
选 b²,为较短前缀提供恰两个 b。
a²b² 数相同必须接受;a⁵b² 有五 a 两 b 必须拒绝。
两运行处理后缀时状态相同,确定性迫使后续状态与最终答案相同,与要求矛盾。
解释最终答案 正确 DFA 中两前缀不能共状态。需要任意多区别,因此排除有限 DFA。
完整推导一道题 · 02 有界版本是正则 设 L₃={aⁿbⁿ:0≤n≤3},给正则表达式,并解释为何无限语言证明不能原样套用。
先选择方法 枚举有限 n 值,无需无界计数器。
n=0 得 ε,n=1 得 ab。
n=2 得 aabb,n=3 得 aaabbb,没有其他允许 n。
取并 ε|ab|aabb|aaabbb,有限表达式正则地描述四串。
解释最终答案 L₃ 正则。先前证明需要任意多个必须区分的前缀,这里固定上限消除了它。
检验推理 a⁴b⁴ 虽数相等仍拒绝,因为 n=4 超过上限。
Leon 的进一步思考 量词承担证明 状态数 m 任意。证明某个三状态机失败,弱于从任意有限 m 出发推出矛盾。
上限改变语言 限制 n≤3 只剩 ε,ab,aabb,aaabbb。有限列表总可识别,尽管无界模式不能用有限记忆。
注意这个边界. 画不出 DFA 不是非正则证明,必须排除每个可能有限 DFA。
检查自己的理解: {aⁿbⁿ:0≤n≤20} 非正则吗? 不是。它有限,可用 DFA 或显式表达式有限并识别。无界要求才驱动不可能性证明。
↑ 返回知识框架 COMP2022 / 10 Leon
文法与递归结构 01 / 从一个故事开始 嵌套收纳盒可选择空隔间,或在大盒里包一个小盒。指令可以引用自身,因此有限配方生成任意深度嵌套。上下文无关文法类似:有名称的未完成组件可替换为终结符与更多未完成组件。只有全部完成才得到成品。类比解释递归,却不规定实际执行顺序。不同替换次序可能描述同一结构、生成同一串。
02 / 理解原理 CFG 包含非终结变量、终结符、产生式和起始变量。每条规则将一个非终结符替换为有限序列,也可替为 ε。“上下文无关”表示无论邻近符号是什么,都可应用规则。推导从起始变量开始,只有全为终结符的结果才属于语言。
文法可描述超出有限状态记忆的嵌套。正确性有两个方向:生成串都符合目标,目标串都能生成。上下文无关语言对并、连接、星封闭:先改名避免变量冲突,再加新起点选择、连接或重复。它们不像正则语言那样对任意交与补封闭。每个正则语言都上下文无关,反向不成立。
先认识这些词
非终结符 仍需重写的命名组件。
终结符 允许出现在完成串中的符号。
推导 从起始变量出发的一系列规则应用。 04 / 先看一个完整例子 用 S→[S]S|ε 生成平衡方括号。生成 [][]:先 S⇒[S]S,把内部 S 替 ε 得 []S,再展开余 S 为 [S]S,最后消去两个 S。生成 [[]] 则改为展开内部 S。任意非空平衡串的第一个 [ 都有匹配 ],把串分成平衡内部及平衡后缀,恰对应两个 S。该分解支持按串长归纳证明。
一步步想清楚 有限文法为何可生成无限多个串? 递归规则可应用任意有限次数。
aSb 已经是语言成员吗? 只要 S 仍是非终结符就不是,必须完成剩余工作。
生成几个例子就证明完备吗? 不能,必须解释每个目标串如何生成。
完整推导一道题 · 01 生成镜像串 文法 S→aSa|bSb|ε,字母表 {a,b}。完整推导 abba,并说明所有生成串共有性质。
先选择方法 匹配外层相同符号,递归中间,以 ε 结束。
abba 外符号为 a,因此 S⇒aSa。
内部目标 bb,因此把 S 替 bSb,得 aSa⇒abSba。
剩余 S 替 ε,得 abba,无变量。每次包裹添加两个相同端符号。
解释最终答案 S⇒aSa⇒abSba⇒abba。每个生成串都是偶长度回文。
检验推理 aba 虽回文却为奇长,文法不能生成;长度不变量解释原因。
完整推导一道题 · 02 用新名称构造连接 G₁ 为 A→aA|ε,G₂ 为 B→bB|b。构造前者串一条接后者串一条的文法,再推导 aab。
先选择方法 保留不相交变量 A、B,用新起点将其连接。
加 S→AB。A 生成零个或多个 a,B 生成一个或多个 b。
两次 A 递归后用 ε:S⇒AB⇒aAB⇒aaAB⇒aaB。
用 B→b 得 aab。两组件顺序固定,任何规则都不能将 a 放到 b 后。
解释最终答案 文法生成 a*b⁺,即任意 a 块后接非空 b 块,并可生成 aab。
检验推理 A 立即消失时允许 b;B 无法消失,所以不含 ε。
Leon 的进一步思考 可靠性与完备性不同 只生成 ε 的文法对平衡括号是可靠却不完备的。它不生成坏串,却漏掉所有非空好串。
组合前先改名 两文法都可能用 S 表示不同内容。连接前先改名,否则规则可能发生意外交互。
注意这个边界. [S] 仍有非终结符,是中间形式,不是已生成终结串。
检查自己的理解: S→aS|b 生成什么语言? 恰为 {aⁿb:n≥0}。每次递归加一个前导 a,最后规则添加 b 并结束。
↑ 返回知识框架 COMP2022 / 11 Leon
解析树与歧义 01 / 从一个故事开始 书面表达式像缺少分组标记的装配指令。先拼前两块或先拼后两块,可能从相同符号造出不同结构。解析树把结构写清:叶是可见串,内部节点记录文法如何组装。独立工作的不同先后顺序不一定改变结构。歧义关乎不同树,因此不能仅列两种任意规则应用顺序就断言有歧义。
02 / 理解原理 解析树记录推导的层级结构。根为起始变量,内部节点按产生式展开,叶从左到右组成结果串。若某串有两棵不同解析树,等价地有两条不同最左推导,则文法有歧义。
E→E+E|E×E|n 没规定优先级和结合性,因此有歧义。分层文法让表达式用加法组合项,项用乘法组合因子,因子提供原子或括号。歧义属于特定文法,不能由一份有歧义文法断言语言没有无歧义文法。可靠求值或翻译前须先确定结构。
先认识这些词
解析树 展示哪些规则构造该串的层级树。
优先级 决定哪个运算结合得更紧的规则。
结合性 同级重复运算如何分组。 04 / 先看一个完整例子 E→E+E|E×E|n 对 n+n×n 可有根为加或根为乘的树。三个 n 分别取 2、3、4,则 2+(3×4)=14,而 (2+3)×4=20。用 E→E+T|T,T→T×F|F,F→n|(E) 可让乘法先在项内形成,再由加法组合。括号仍能明确要求另一结构。
一步步想清楚 两条任意推导为何不够? 它们可能只在不同次序展开独立分支,仍是同一树。
同一表达式如何有 17 与 27? 5+4×3 若为 5+(4×3) 得 17,若为 (5+4)×3 得 27。
加乘优先级能决定减法结合性吗? 不能。重复减法还需独立分组规则。
为什么一次切分内部相乘,不同切分之间相加? 一次切分中,每棵左树可与每棵右树配对;不同切分下,一棵树的根划分唯一,因此集合互不重叠。
完整推导一道题 · 01 两棵树产生不同结果 使用 E→E+E|E×E|n,其中 n 表示一个数字记号。三个数字记号依次显示数值 5、4、3。给出 5+4×3 的两种解析并求值。
先选择方法 保持叶顺序不变,选择不同根运算。
根选 +,左叶 5,右子树 4×3。先乘得 12。
根相加 5+12=17,该树为 5+(4×3)。
改根为 ×,左子树 5+4=9,右叶 3,根值 9×3=27。
解释最终答案 两树给相同无括号文字,却得 17、27,证明文法有歧义。
检验推理 加显式括号可区分两个所求结构,消除这次歧义。
完整推导一道题 · 02 展开顺序不是树歧义 文法仅 S→AB、A→a、B→b。比较先展开 A 与先展开 B。
先选择方法 写两推导,再比较父子结构。
先 A 得 S⇒AB⇒aB⇒ab。
先 B 得 S⇒AB⇒Ab⇒ab。
两树均根 S,子为 A、B,A 下 a、B 下 b,没有产生式选择不同。
解释最终答案 两种调度描述同一解析树,不构成歧义;该文法无歧义。
检验推理 只有第一种始终最左展开,从而排除无关次序差异。
完整推导一道题 · 03 用小规模结果算出五棵树 对 E→E+E | n,计算 T(4),不要枚举所有推导顺序。
先选择方法 按根切分数树结构。不同节点展开顺序可能得到同一棵树,不能重复计数。
T(1)=1,T(2)=T(1)T(1)=1。
T(3)=T(1)T(2)+T(2)T(1)=2。
T(4)=T(1)T(3)+T(2)T(2)+T(3)T(1)=2+1+2。
解释最终答案 共有五棵语法树。程序打印五种不同的完全括号化形式。
检验推理 三个操作数的两棵树是 ((n+n)+n) 和 (n+(n+n)),可核对第一个非平凡情形。
运行一个完整示例 · 01 数清语法树,不要默认只有一种解析 计算器接受 n+n+n+n。米娜先合并第一对操作数,朋友却先合并最后一对。两种做法都符合 E→E+E | n。字符串合法,但结构并不唯一。米娜枚举根节点的所有切分,再组合左右子树,最终找到五棵树,也理解了解析器为什么需要结合性规则。
Python 3 复制代码 下载源代码 ↓ 长代码行可左右滚动。复制或下载会保留原始代码。
from functools import lru_cache
def count_trees ( operands ):
if operands < 1 :
raise ValueError ( "at least one operand required" )
ways = [ 0 ] * ( operands + 1 )
ways [ 1 ] = 1
for size in range ( 2 , operands + 1 ):
ways [ size ] = sum ( ways [ left ] * ways [ size - left ]
for left in range ( 1 , size ))
return ways [ operands ]
@lru_cache ( None )
def trees ( operands ):
if operands == 1 :
return ( "n" ,)
return tuple ( f "( { left } + { right } )"
for cut in range ( 1 , operands )
for left in trees ( cut )
for right in trees ( operands - cut ))
assert [ count_trees ( n ) for n in range ( 1 , 6 )] == [ 1 , 1 , 2 , 5 , 14 ]
assert len ( set ( trees ( 4 ))) == count_trees ( 4 )
print ( "four operands:" , count_trees ( 4 ), "parse trees" )
for tree in trees ( 4 ):
print ( tree )
在本地运行 python parse-trees-ambiguity-count-expression-trees.py 预期输出 four operands: 5 parse trees
(n+(n+(n+n)))
(n+((n+n)+n))
((n+n)+(n+n))
((n+(n+n))+n)
(((n+n)+n)+n)
按执行顺序理解 一个操作数对应一棵叶子树,基础值是一,不是零。
根在 left 个操作数之后切分时,左右树数量相乘,每对左右树构成一棵树。
对不同根切分求和;根的划分不同,不会得到同一棵有序树。
只枚举四个操作数用于展示。计数与实际生成全部树,输出成本差别很大。
逐步读懂代码 设 T(m) 表示 m 个相同操作数词元用加号连接时的语法树数量。T(1)=1,T(m)=对 k=1 到 m-1 求和 T(k)×T(m-k)。k 表示左子树的叶子数量。m=4 时,三种根切分分别贡献 1×2、1×1、2×1,总数为 5。
计数器需要 O(m²) 次算术操作,并保存 O(m) 个整数。大计数需要大整数,因此这里没有声称任意大 m 下算术仍是常数成本。枚举所有树至少要花费与输出字符数相关的时间,增长快得多。
算出的数值相同,不表示文法无歧义。歧义指同一词元字符串具有多棵语法树。对这个简单语言,E→E+n | n 可以规定左结合。本例假定已经分词且只有加号,并未实现词法分析、其他运算符优先级或通用文法解析器。
Leon 的进一步思考 同值可能掩盖歧义 1+2+3 两树都算六,但仍不同。数值相等不能证明文法无歧义。
修文法而非猜结构 分表达式、项、因子可将优先级写入语法。求值器据树计算,无需事后添加可能矛盾的规则。
注意这个边界. 仅以不同次序展开独立分支并不构成歧义。应比较树或最左推导。
检查自己的理解: 有歧义文法能生成正则语言吗? 能。歧义关乎表示,不是表达类别。例如 S→A|B、A→a、B→a 对有限正则语言 {a} 给两种解析。
↑ 返回知识框架 COMP2022 / 12 Leon
不改变语言的 Chomsky 范式 01 / 从一个故事开始 设装配说明只能有两种形状:连接两个未完成组件,或安装一个完成零件。复杂指令拆成小阶段,可选组件和别名需谨慎处理,确保新说明仍生成相同成品。Chomsky 范式为文法规则提供这种形状。目的不是最短或最优雅,而是让解析容易推理。空成品例外单独保留,因为有可见叶的树无法表示无零件成品。
02 / 理解原理 CNF 普通产生式只能 A→BC 或 A→a。若语言含 ε,新起点还可 S₀→ε,且新起点不可出现在任何右侧。转换通过为长规则中终结符引入变量、将长右侧拆成二元规则、为可空变量添加所有所需省略选择,以及按别名可达关系移除单位规则来保留语言。
顺序与记录很重要:可空变量可重复出现,只删 ε 规则而不添选择会丢串。长 n 的非空词的 CNF 树有 n 个终结生成节点、n−1 个二元节点。该受限结构支持可判定成员检查与动态规划。
先认识这些词
Chomsky 范式 规则限两个变量或一个终结符,另有受保护起点例外。
可空 变量能够推导 ε。
单位产生式 右侧仅一个变量的 A→B 规则。 04 / 先看一个完整例子 从 S→aS|b 开始,引入 A→a,使混合规则变 S→AS。因 S 在右侧出现,加入新起点 S₀→S。去单位规则时复制 S 的非单位规则,得 S₀→AS|b、S→AS|b、A→a。
仍生成 aⁿb。对 aab:S₀⇒AS⇒aS⇒aAS⇒aaS⇒aab,共五次,与 2×3−1 一致。不同展开顺序计数仍一样,因为树节点数固定。
一步步想清楚 为何引入终结符辅助变量? 二元 CNF 规则须是两个变量,不能是 aB 这样的混合。
CNF 生成四终结符要几步? 四个终结规则加三个二元规则,共 2×4−1=7。
ε 能用相同正长计数吗? 不能。它无终结叶,使用独立起点例外。
完整推导一道题 · 01 转换长度三规则 文法 S→aBC、B→b、C→c 只生成 abc。转换到 CNF 且不改变语言。
先选择方法 先分离长规则中的终结符,再把三个变量拆为二元步骤。
加入 A→a,用 S→ABC 替代 S→aBC,生成符号不变。
加入 X→BC,并将长规则改 S→AX。S 每步产生两个变量。
保留 B→b、C→c。S→AX、X→BC、A→a、B→b、C→c 均符合形式。
解释最终答案 CNF 文法仍恰生成 abc,每次解析用两个二元、三个终结产生式。
检验推理 n=3 时 2n−1=5,与五次相符;没有其他规则可生成别的串。
完整推导一道题 · 02 删除重复可空变量 文法 S→AA、A→a|ε。转为保语言 CNF,允许 S 作受保护起点,且 S 不在右侧出现。
先选择方法 移除空与单位规则前,枚举两个 A 独立保留或省略。
保留两 A 得 S→AA,删一个得 S→A,两种删法得到同规则。
都删得 S→ε,因为 S 受保护,允许该空规则。
删除 A→ε,保留 A→a。把单位 S→A 替为 S→a。最终 S→AA|a|ε、A→a。
解释最终答案 两文法均恰生成 {ε,a,aa},最终是带所述起点例外的 CNF。
检验推理 若删 A→ε 却不添 S→a、S→ε,就会丢掉三串中的两串。
Leon 的进一步思考 先保留选择再删除 变量可消失时,每个相关出现都能保留或省略。先删 ε 规则可能悄悄删掉短词。
范式是工具 CNF 可能增加很多辅助变量。收益是可预测二叉解析结构,不一定文法更小或文字更短。
注意这个边界. 右侧长度不超过二并不就属于 CNF。A→B 是单位规则,A→aB 混合终结与非终结符,都需转换。
检查自己的理解: B→AA 中 A 可空,需要哪些更短选择? 除 B→AA 外可能需 B→A、B→ε。随后删除不允许的空与单位规则,同时保留起点例外。
↑ 返回知识框架 COMP2022 / 13 Leon
CYK:从短片段构造长解析 01 / 从一个故事开始 校对者先给单词贴标签,再处理两个词和更长片段。只有长片段可分成两个已理解且符合规则的短片段时,才给它标签。表格存结果避免重做。CYK 对 CNF 文法采用此计划,不把有希望的分界当成唯一分界,而会检查所有边界。表格直接回答成员资格,若保存成功选择,还能还原解析树。
02 / 理解原理 使用左闭右开区间:T[i,j] 是生成 w[i:j] 的非终结符集合,边界为 0 到 n。用终结规则初始化长度一,再按长度 2 到 n 处理。对每个 i<k<j 和 A→BC,若 B∈T[i,k]、C∈T[k,j],则加入 A。依赖都是更短片段,因此顺序有效。
非空词接受当且仅当起始变量在 T[0,n]。ε 按起点例外单独处理。直接扫描二元产生式时,时间 O(|P|n³),成员存储 O(|V|n²)。固定文法下分别为三次时间、二次空间。
先认识这些词
片段 两个边界之间的连续子串。
动态规划 存储短子问题答案并用于更大问题。
左闭右开区间 包含开始位置而不包含结束位置。 04 / 先看一个完整例子 用 S→AB、A→AA|a、B→b 解析 aab。初 T[0,1]={A}、T[1,2]={A}、T[2,3]={B}。长二时,A→AA 将前两格合成 T[0,2] 中的 A;S→AB 将末 a,b 合成 T[1,3] 中的 S。
整串在 k=2 处分割,A∈T[0,2]、B∈T[2,3],故加入 S 并接受。短格已有 S 并不足够,必须整串格含 S。记录分界可还原树 S(A(A(a),A(a)),B(b))。
一步步想清楚 为何每格存集合? 多个变量可能生成同子串,并用于不同父规则。
abc 中 T[1,3] 覆盖什么? 位置 1、2,即 bc;3 只是结束边界。
短格含 S 能证明全串接受吗? 不能,起始变量须在覆盖全串的格中。
完整推导一道题 · 01 填写小型 CYK 表 CNF 文法 S→AC、C→BB、A→a、B→b。用边界 0,1,2,3 解析 abb。
先选择方法 先初始化字母再扩大片段,保证先子后父。
长一格为 T[0,1]={A}、T[1,2]={B}、T[2,3]={B}。
长二时 ab 无可用二元规则,T[0,2]=∅。两 b 用 C→BB 合并,T[1,3]={C}。
整段在 k=1 分开:前格 A、后格 C 满足 S→AC,因此加入 S。
解释最终答案 S∈T[0,3],因此接受 abb,树为 S(A(a),C(B(b),B(b)))。
检验推理 文法无其他选择,因此唯一可能终结串确为 abb。
完整推导一道题 · 02 字母合法仍拒绝 使用相同文法 S→AC、C→BB、A→a、B→b,测试 bab,解释整格失败。
先选择方法 检查全部二元分界,不能只看每个字母有终结规则。
b,a,b 的对角格为 {B},{A},{B},每字母都可识别。
ba、ab 都不匹配唯一长二规则 C→BB,因此两个长二格都空。
k=1 时右格空,k=2 时左格空,两者都无法提供 A 后接 C。
解释最终答案 T[0,3]=∅,拒绝 bab。符号合法不保证结构合法。
检验推理 对照接受的 abb,只有它把 a 放在所需双 b 区域之前。
Leon 的进一步思考 保留全部成功分界 成员判断只需知道变量是否存在。若要恢复全部解析,则每个成功规则与分界都须保留,而非一个指针。
三次来自循环结构 区间数量为二次,每区间可有线性分界数。扫描文法另加因子;固定文法三次时间不意味着成本固定。
注意这个边界. 不要混用含端点与不含端点。T[i,j] 对应 w[i:j] 时,子格必须 T[i,k]、T[k,j],不可漏或重复字符。
检查自己的理解: 为何不随意顺序填片段? 格子依赖更短片段。递增长度确保所有子问题先完成。
↑ 返回知识框架 COMP2022 / 14 Leon
图灵机与配置 01 / 从一个故事开始 想象细心书记员拿长方格纸、铅笔和小指令卡。卡片根据当前模式与笔下符号决定动作,一步可改符号、移动一格并换模式。不同于有限自动机,他可回看旧格并留记号。纸带提供可扩展记忆,指令仍有限。无限纸带是可用存储无固定上限的理想化,并非一步做无限操作。
02 / 理解原理 图灵机由有限控制、可读写纸带、可移动读写头组成。带字母表含输入符号、空白及可能标记。配置记录状态、头位置与纸带内容,转移决定下一配置。有限次计算后,绝大多数格仍空白。
机器可停机接受、停机拒绝或永远继续。作为函数计算器时,要规定输出编码和头最终位置。单向或双向带、允许原地不动等标准约定改变描述,但不改变可计算函数范围。时间与模拟开销仍可能不同。
先认识这些词
配置 当前状态、头位置与带内容的整体。
带字母表 可写符号全集,包括空白与标记。
转移 一次读取、写入、移动与换状态的规则。 04 / 先看一个完整例子 机器扫描二进制串,将每个 0 改为 1,原 1 不变。scan 状态读 0 或 1 都写 1、右移并保持 scan;读空白进入停机且不改带。输入 010 从首位开始,非空带依次 110、110、111,再一次看到空白后停机。空输入立即停机。有限状态不存整词,纸带记录不断变化的输出。
一步步想清楚 为何只有状态还不算配置? 同状态可能处在不同格或符号上,下一步会不同。
从位置 2 右移会怎样? 写完当前格后,下一头位置为 3。
无界纸带意味着每步无限工作吗? 不是,每步只访问一个格并有限移动。
完整推导一道题 · 01 跟踪翻转位机器 scan 中读0写1右移;读1写0右移;读空白写空白原地停机。101 位于 0–2,头从 0 开始。跟踪到停机。
先选择方法 每步记录纸带与头,控制状态不变不表示无事发生。
位置0读1写0,头到1,带为001。
位置1读0写1,头到2,带为011。
位置2读1写0,头到空白位置3,带为010。第四转移看到空白,在此停机。
检验推理 再翻转输出各位得到原101,独立验证变换。
完整推导一道题 · 02 从配置求唯一后继 带位置0,1,2为a,b,空白。头在1,状态q。规则 δ(q,b)=(r,X,L)。求下一配置。
先选择方法 读指定格,分开处理写入、移动、控制更新。
头位置1是b,因此规则适用;本步不读位置0的a。
将位置1换X,带成a,X,空白,其他格不变。
从1左移到0,状态q改r。新头下a在下一转移才被读取。
解释最终答案 下一配置为状态r、头0、纸带aX后接空白。
Leon 的进一步思考 说明输出约定 若有效数字间留临时标记,只说输出在带上不完整。须指明输出格和是否擦标记。
统计停机转移 扫描器通常还需一步看到数据后的首空白。只数改变的格可能少算,即使某些写入没改符号。
注意这个边界. 缺失转移、拒绝和无限循环不等价。须说明约定,区分停机结果与发散。
检查自己的理解: 标准图灵机能有无限多个状态吗? 不能。控制描述有限,无界工作存储来自纸带。
↑ 返回知识框架 COMP2022 / 15 Leon
用标记与不变量设计机器 01 / 从一个故事开始 书记员检查两组物品是否配对:先标左组一件,走到右组标一件,再回去重复。标记让记忆跨行走保留。右组提前用完或结束时还有未配物品就失败。这适合比较需要无界记忆而控制模式有限的任务。好的设计要说明每趟保证什么,以及有限输入为什么不可能无限往返。
02 / 理解原理 图灵机实现描述可先用阶段而非立即列全部转移。规定每阶段不变量、预期标记、成功与失败出口。对 aⁿbⁿ,先检查输入是一个 a 块后接 b 块,再反复标最左未标 a、找一未标 b、返回左边界。缺伙伴即拒绝;a、b 全标完才接受。
每成功轮未标 a 数严格下降,证明终止。每轮可扫描 O(n) 格,共 O(n) 轮,因此此简单单带实现有 O(n²) 上界,不是所有算法的普遍下界。
先认识这些词
标记 记录位置已被处理的带符号。
阶段 服务于明确目标的一组步骤。
终止度量 重复推进时严格下降的非负量。 04 / 先看一个完整例子 对 aaabbb,形状检查后每轮带为 XaaYbb、XXaYYb、XXXYYY,最后无未标字母而接受。对 aabbb,两轮 XXYYb,剩 b 而拒绝。abab 有 a 出现在 b 块之后,先被形状检查拒绝。三例分别测试数量相等、数量不等、次序错误。只比数量会误接受某些混合顺序串。
一步步想清楚 配对前为何检查顺序? 仅数量相等也会接受abab等混合串。
完成一轮保证什么? 恰好新增一个已标a和一个已标b。
二次界是普遍下界吗? 不是。它限制本重复扫描设计,不限制所有模型或算法。
完整推导一道题 · 01 伙伴不足时拒绝 用X标a、Y标b,对aaaabb运行有序块配对算法,每轮标最左未标a和b。
先选择方法 先跟踪完整成功轮,再定位首次缺伙伴。
形状a*b*合法。首轮配一a一b,得XaaaYb。
第二轮得XXaaYY,还剩两个a,b却全标。
第三轮选a得XXXaYY,但向右直到空白无未标b,明确失败并拒绝。
解释最终答案 拒绝aaaabb,因为四个a无法与两个b一一配对。
检验推理 直接计数4≠2核实结果,机器有限控制无需保存数字四。
完整推导一道题 · 02 证明配对循环停机 输入为有限a块后接b块,总长n,每次扫描到带边界或明确失败便结束。证明不能完成无限多配对轮。
先选择方法 以未标a数作为下降非负整数。
初始未标a数为u,0≤u≤n。
每成功轮恰标一个旧未标a,度量u→u−1,且无规则恢复。
至多初始u轮后计数零。缺b可更早拒绝;最终残余b检查也只是有限扫描。
解释最终答案 所有允许输入都终止。至多n轮、每轮O(n),给此实现O(n²)上界。
检验推理 u=0时无配对轮,最终扫描仍区分ε与非空b块。
Leon 的进一步思考 区分失败类型 顺序错立即拒绝,所选a无伙伴拒绝,结束残余b拒绝。各检查填补不同正确性缺口。
下降计数还需要阶段有限 未标a减少只能证明成功轮有限,还须每轮扫描能到边界或明确失败。停机论证要包含这点。
注意这个边界. 不能只证接受者正确而忘记终止或漏拒未配符号。判定器需要双向正确性与停机证明。
检查自己的理解: 状态能记信息,为什么还需要标记? 标记在纸带保存无界数量的局部事实,固定有限状态无法记任意多个访问位置。
↑ 返回知识框架 COMP2022 / 16 Leon
模拟、通用性与 Church–Turing 论题 01 / 从一个故事开始 通用播放器读取乐谱就能播放不同曲子,无需为每首重造硬件。通用图灵机同样读取机器编码及其输入,逐步解释。类比也显出限制:能跟乐谱不代表事先知道古怪乐谱会否要求无限重复。通用性是模拟任意编码程序的能力,不是无需执行便预测每个程序最终行为的能力。
02 / 理解原理 通用图灵机 U 从有限编码 ⟨M,w⟩ 模拟 M 在 w 上运行,保留接受、拒绝或不终止结果。有限字母表、状态及转移表可编码为有限串,因此机器描述能作为数据。两种形式模型等价需双向模拟,单向仅证能力包含。
Church–Turing 论题把非形式的有效算法计算与图灵可计算联系起来,是关于“算法”的论题,不是仅靠定义 TM 就证明的定理。通用性与标准纸带变体等价是具体数学定理。可计算能力相同本身不保证速度、内存或实用性相同。
先认识这些词
编码 表示机器或输入的有限串。
通用机器 能模拟编码机器的单一解释器。
模拟开销 复现另一模型步骤所需额外工作。 04 / 先看一个完整例子 M 在一元输入末尾添加一个1后停机。向 U 给 M 编码及111。U 存模拟状态和头位置,查编码规则、更新模拟带并重复直到停机,模拟输出1111。换成一直右移的机器,U 也一直运行。同一解释器处理两者,说明通用性并不提供停机测试。
一步步想清楚 机器描述为何能作输入数据? 其有限规则可列出并用有限符号编码。
模拟一个循环会让它停机吗? 不会,忠实模拟保留不终止。
为何需要双向模拟? 单向只证模拟器能力至少包含被模拟模型。
完整推导一道题 · 01 模拟简单加一器 M 向右扫描一元1,在首空白写一个额外1并停机。输入11,头在首符号。说明模拟输出与步骤。
先选择方法 保留模拟带、头和状态,一次应用一个编码规则。
首步读位置0的1,保持并移到1。
第二步读位置1的1,移到空白位置2。
下一规则在位置2写1并停机,模拟带现为111。
解释最终答案 模拟输出111,表示一元三。按约定 M 用三次转移。
检验推理 通用解释器可能用超过三次自身转移实现这三步。
完整推导一道题 · 02 跟踪明确模拟开销 教学解释器每模拟一步需自身6步,准备10步。被模拟程序7步停机。求解释器总工作,再讨论被模拟程序不停止的情形。
先选择方法 区分固定准备与逐步成本,再区分有限成本和保留发散。
七模拟步耗7×6=42解释器步。
加一次准备:42+10=52。这是题给成本模型,不是普遍界。
若被模拟程序无限运行,逐步复现也需要无限解释器步。
解释最终答案 停机例耗52步;忠实模拟不停止例也不会停机。
检验推理 模拟步数零时只剩准备10,与10+6t一致。
Leon 的进一步思考 行为与资源不同 两模型可计算相同函数却用很不同步数。讨论模拟应同时说明保留结果与资源关系。
坏编码也是输入 通用解释器要识别机器描述边界,并按约定拒绝坏格式,否则形式输入行为不完整。
注意这个边界. 不能说论题证明所有可想象物理设备都与 TM 等价,也不能说模拟保证效率相同。
检查自己的理解: Python 能模拟 TM 就证明二者能力相同吗? 不能。这只说明 Python 能模拟 TM,还需反向证明相关 Python 计算模型可由 TM 模拟。
↑ 返回知识框架 COMP2022 / 17 Leon
识别器与判定器 01 / 从一个故事开始 失物处找到匹配标签就能确认包已到,但没找到时可能无限搜。另一处承诺查完有限完整登记册,总回答是或否。前者类似识别,后者类似判定。久等前者并不能把沉默当可靠否定。区别是对全部输入的保证,不是已观察请求上是否友好或快。
02 / 理解原理 语言识别器必须接受每个成员,绝不接受非成员;对非成员可拒绝或永远运行。判定器还要求每输入停机,因此每成员问题都得到正确是或否。每个可判定语言都可识别,但反向不成立。
对编码机器的接受问题,通用模拟识别肯定例:若被模拟机器接受,迟早会观察到;若拒绝可拒绝,若循环也可循环。有限测试不能证明程序为判定器,因为未测输入可能发散。证明既需全部允许计算终止,也需答案正确。
先认识这些词
识别器 接受所有成员且不接受非成员,但可在非成员上循环。
判定器 对每输入给正确成员答案并停机。
见证 能建立肯定答案的有限对象。 04 / 先看一个完整例子 程序依次试0,1,2,…,若找到满足输入谓词 P(x) 的整数就接受,假设每次 P 检查会停机。有见证就迟早遇到并接受,无见证则一直找,所以它识别见证存在性,却未自动判定。P 为 x²=49 时在7接受,P 为 x²=50 时在非负整数上一直搜,虽然该特殊家族可另设计有界判定。一个循环实现不能证明语言不可判定。
一步步想清楚 识别器沉默可能意味着什么? 可能尚未找到未来见证,也可能永远搜,沉默本身无法区分。
为什么判定器都是识别器? 正确接受已满足识别,还多保证否定例也停止。
可判定语言也能有很差识别器吗? 能。可判定性问某判定器是否存在,不保证每个实现好。
完整推导一道题 · 01 在简单否定例上循环的识别器 输入n≥0,依次测试x=0,1,2,…,x²=n时接受,每次平方检查会停。比较16与18。
先选择方法 区分见证存在与无见证时终止。
n=16时测试0,1,4,9,16,x=4提供见证并接受。
n=18时4²=16、5²=25,后续非负平方继续增长,故无解。
指定程序没有超过n后停止的规则,因此在18上永远试,尽管数学上能拒绝。
解释最终答案 该程序识别完全平方数但不判定;接受16,在18上发散。
检验推理 另一个程序可在x²>n时拒绝,所以循环例不证明平方语言不可判定。
完整推导一道题 · 02 把特殊搜索变为判定器 修改平方搜索:整数n≥0,测试x从0到n,含端点;相等接受,循环结束否则拒绝。证明正确与终止。
先选择方法 证明有限范围包含每个可能非负平方根。
n=0只需x=0且成功。n≥1时x>n则x²≥x>n,不可能为解。
循环检查n+1候选,每次会停,因此整体有限。
相等提供真实见证;充分范围中无相等就不存在非负整数解,因此拒绝正确。
解释最终答案 有界过程判定平方数成员资格,更紧上界可提速但不改答案。
检验推理 n=1时包含x=1,漏掉上端点会错误拒绝边界例。
Leon 的进一步思考 证明要涵盖全部终止 十条轨迹停只证明十例。覆盖每个允许输入的上界或下降度量才补全一般论证。
限制可能使搜索有限 若证明可计算有限上界足够,无界见证搜索可变判定器。上界须来自问题,而非任意超时。
注意这个边界. 不能由超时推非成员,也不能因某算法循环就推不可判定。
检查自己的理解: 识别器可拒绝某些非成员、却在其他非成员上循环吗? 可以。语言外两种行为都允许,唯独不能接受。
↑ 返回知识框架 COMP2022 / 18 Leon
为什么通用停机测试不可能 01 / 从一个故事开始 想象目录声称分类每个可能检查目录的程序,包括读取自己条目的程序。一个调皮程序可查看对自己的预测,再故意反着做。若目录总正确且总回答,自指就产生矛盾。问题不是太慢或内存少,而是完整过程能否存在。真实分析工具仍有用,因为可限制程序类型、允许未知,或只保证部分问题而非回答所有程序的一切。
02 / 理解原理 假设全停机算法 H 能判定任意编码机器在任意输入是否停机。构造 D:输入机器描述x,问 H(x,x);若答是就永远循环,若答否就停机。让 D 读取自己的描述,两答案都与行为矛盾,因此不存在全正确且全停机的 H。
停机语言仍可识别:模拟直到任何停机结果。接受问题也可识别却不可判定。相关对角语言为不接受自身描述的机器描述,它不可识别,因为任何候选识别器都会在自身描述上与定义冲突。形式证明要一致处理编码与坏输入。
先认识这些词
不可判定 没有算法对每允许输入都停机并答对。
对角化 利用构造自身描述强制产生分歧。
全停机算法 保证在定义域每输入上停机的算法。 04 / 先看一个完整例子 若 H 预测 D 在 ⟨D⟩ 上停机,D 见是后故意循环,预测错。若 H 预测不停机,D 见否后立即停止,仍错。两情况穷尽判定器布尔答案。允许第三答案“未知”避开矛盾,却不再判定原问题。限制固定步数的程序也可有界模拟,但这是另一输入类别。
一步步想清楚 对 H 假设什么? 它对每合法机器输入对都正确回答且总停机。
预测是后 D 做什么? 故意循环,反驳其会停的预测。
未知能避开矛盾吗? 可以,但 H 就不是覆盖全部输入的判定器。
完整推导一道题 · 01 补全自指两种情况 假设 H 是全正确全停机判定器。D(x) 在 H(x,x)=是时循环,为否时停。分析 H(⟨D⟩,⟨D⟩)。
先选择方法 穷尽两种布尔答案,不猜实际是哪种。
若 H 答是,预测 D 在自身描述停;但 D 的是分支永远循环。
若 H 答否,预测 D 不停;但 D 的否分支立即停。
因 H 全停机,必须返回两者之一,而两者都违反正确性,因此初假设失败。
解释最终答案 不存在适用于任意编码程序与输入的全正确全停机判定器 H。
检验推理 若 H 可不返回,第三步就不可用。证明针对完整判定器,不针对部分工具。
完整推导一道题 · 02 有界问题可判定 给有限机器描述 M、输入 w、非负整数 B,判定 M 是否至多 B 次转移内停机。包括 B=0。
先选择方法 给定有限界允许完整模拟到该界,只回答有界问题。
检查初始配置,若已是指定停机配置,即使 B=0 也答是。
否则最多执行 B 次合法转移,每步后查停机,出现则答是。
若检查配置都不停,则对“B内”答否。计数器限制模拟,所以过程自身停机。
解释最终答案 有界停机可判定。否表示界内没停,不表示永远不停。
检验推理 在 B+1 步停的机器被有界问题正确拒绝,却属于无界 HALT。
Leon 的进一步思考 别混淆停机与接受 停机拒绝也属于 HALT。因此 HALT 识别器在任一种模拟停机后都应接受,不仅模拟接受时。
有用工具仍然可能 检查器可对有下降整数计数器的受限循环语言证明终止,这不违反涵盖任意程序的定理。
注意这个边界. 定理不表示程序永远不能证明其他程序会停。它只排除适用于所有程序输入的完整、总正确判定器。
检查自己的理解: 证明为什么要求 H 每输入都停止? D 须收到 H 答案才选择相反行为。若 H 可循环或答未知,就没有完整判定过程。
↑ 返回知识框架 COMP2022 / 19 Leon
交错模拟与补语言 01 / 从一个故事开始 两位调查员分别寻找同一主张的真证书与假证书。若让第一位一直独占直到完成,第二位可能永无机会。改给交替时段,只要其中一位保证迟早找到相应证书,就能获得结论。这叫交错模拟。它不会凭空造证书,力量来自每个输入恰属于两个可搜索方面之一。
02 / 理解原理 可判定语言对补、并、交封闭,因为判定器总结束。交换接受与拒绝即可补判定器。可识别语言对并、交封闭,却不保证对补封闭。并可公平模拟两个识别器,任一接受就接受;若顺序等第一台,可能卡住而错过第二台成功。交则等两台都接受,公平模拟可作为统一构造。
语言可判定当且仅当它与补都可识别。反向证明交错两识别器,必有一个最终接受,从而确定答案。因此可识别却不可判定语言的补不能也可识别。
先认识这些词
交错模拟 公平分配模拟步,避免一过程永远等另一过程。
补语言 允许输入宇宙中不属于该语言的全部串。
接受标志 记录某模拟已接受的事实。 04 / 先看一个完整例子 Ryes 识别 L,Rno 识别其补。输入 z 上,Ryes 永远循环,Rno 在37步接受。先等 Ryes 的顺序策略永无答案。每台交替一步,至多74个模拟步就看到 Rno 接受,组合过程拒绝 z。若 z∈L,Ryes 保证接受,因此总停机。保证依赖互补语言,两项无关搜索可同时永远不结束。
一步步想清楚 为什么不先跑完一识别器? 它可能在该输入永不结束,阻止另一台找到见证。
交识别器要记什么? 各组件是否已接受,两个标志都真才接受。
互补识别器为何给判定器? 每输入恰属于一侧,该侧识别器保证最终接受。
完整推导一道题 · 01 统计公平模拟步 Ryes 识别L,Rno识别补。w上Ryes循环,Rno自身第五步接受。按Ryes再Rno各一步交替,求组合何时回答。
先选择方法 给全局模拟步编号,跟踪各步归谁。
全局1,3,5,7,9归Ryes,不终止其搜索。
全局2,4,6,8,10是Rno第一至第五步,第10步它接受。
补识别器接受证明w∉L,因此组合机器立即拒绝。
解释最终答案 判定器在10个组件模拟步后拒绝,不计调度额外工作。
检验推理 若先等Ryes,则即使证书仅需五步,也永远不会执行Rno。
完整推导一道题 · 02 为什么补不能也可识别 假设L可识别却不可判定。反证假设其补有识别器C,不假设任一识别器对所有输入停机,推出矛盾。
先选择方法 用公平调度与成员互斥性组合两个部分成功过程。
对同输入交替运行L的识别器R与补识别器C。
输入属于L时R最终接受,否则C最终接受,二者都不能在错误侧接受。
R接受则接受,C接受则拒绝,因此每输入都获得正确且终止答案。
解释最终答案 这构造L判定器,与前提矛盾,因此补不可识别。
检验推理 可判定语言则无矛盾:两侧均有判定器,因此均有识别器。
Leon 的进一步思考 公平是一项算法保证 每个活跃过程轮流一步就足够。只说两者都试不完整,因为实现可能不给一方后续机会。
拒绝并非补识别器已就绪 识别器可能拒绝部分外部输入却在其他上循环。仅复用拒绝行为不能覆盖补的每个成员。
注意这个边界. 交换识别器停机标签不能求补,其无限计算仍无限,不会让所有原非接受输入变接受。
检查自己的理解: L 可识别且不可判定时,其补怎样? 补不可识别,否则两侧识别器交错就能判定 L,与不可判定矛盾。
↑ 返回知识框架 COMP2022 / 20 Leon
命题语法与真值 01 / 从一个故事开始 实验室警报板组合门开、风扇开、温度超限等信号。连线说明怎样组合,当前开关值决定警报值。逻辑将两层区分为语法与语义。括号像接线,改变它可能改变结果。模型假设信号有明确真假,并不自动表示测量不确定或因果,因此逻辑蕴含不能当作传感器间物理机制。
02 / 理解原理 命题公式由原子与否定、合取、析取等联结词组成。赋值给每原子布尔值,再按解析树递归算公式值。除非声明异或,析取是包含式。实质蕴含 P→Q 只在P真Q假时为假,P假时为真。
有至少一赋值使真称可满足,每赋值都真称有效,没有真赋值称不可满足。k个原子的完整真值表有2ᵏ行,给有限判定法,但赋值数指数增长,单行容易不代表整体便宜。
先认识这些词
真值赋值 为每原子命题选择真或假。
可满足 至少一个赋值下真。
有效公式 每个赋值下真。 04 / 先看一个完整例子 设p为样本冷藏,q为封口完整,F=p→q。(假,假)、(假,真)、(真,真)都满足,只有(真,假)使假,所以可满足而非有效。再要求p,得p∧(p→q),唯一满足为p=q=真。再要求¬q就无赋值而不可满足。推理排除配置,不是在说冷藏物理上确保封口。
一步步想清楚 三原子为何八行? 各有两选择,2×2×2=8赋值。
p→q何时假? 恰在p真q假时。
可满足公式还能某处假吗? 能。可满足只需一真行,有效才要求全部真。
完整推导一道题 · 01 分类受限制蕴含 原子p,q,分类F=(p→q)∧¬q为可满足、有效或不可满足,使用四赋值。
先选择方法 合取先强制¬q,再检查剩余行的蕴含。
q真时¬q假,因此p两选择都使F假。
q假p真时p→q假,因此F假。
q假p假时p→q真且¬q真,因此F真。
解释最终答案 仅(p,q)=(假,假)满足。F可满足但不有效。
检验推理 改写为(¬p∨q)∧¬q,在¬q下化为¬p∧¬q,核对结果。
完整推导一道题 · 02 统计包含式或的模型 F=(p∨q)∧r,有三个独立布尔原子,或为包含式,统计满足赋值。
先选择方法 将被强制的r与允许的p,q对分开。
合取要求r真,四个r假赋值全失败。
r真时p∨q接受(真,假)、(假,真)、(真,真),不接受(假,假)。
一个r选择配三个对,得1×3=3模型,总赋值2³=8。
检验推理 若或改为异或,则去掉同时真对,模型数降二。
Leon 的进一步思考 从内向外求值 先算括号子公式,再算父联结词,可防止把长公式按自然语句意外分组。
经典蕴含不是因果 真蕴含只排除前提真结论假组合,不解释事件成因,也不给概率。
注意这个边界. “p only if q”应为p→q,不是q→p;only if给必要条件。
检查自己的理解: p∨¬p只是可满足还是有效? 在经典二值语义下有效:p真或p假而¬p真。
↑ 返回知识框架 COMP2022 / 21 Leon
逻辑等价与安全改写 01 / 从一个故事开始 两警报电路外观不同,却可能在每种输入设置下都亮相同灯。一次测试只证明一次一致,等价要求全部一致。代数改写可不看外观而证明一致。替换法须匹配完整子电路,逻辑等价也作用于完整子公式。类比适于布尔行为,但转为有状态表达式的程序时,等价公式不保证求值成本或副作用相同。
02 / 理解原理 F与G在每真值赋值下相同称逻辑等价。它允许在更大公式内用等价子公式替换而不改整体真值。常用双否定、De Morgan、分配、吸收、消蕴含等规则。真值表检查所有行可证明,一条差异行可推翻。
F↔G是在一个赋值下有真值的公式;F≡G是对全部赋值的元层断言。双条件有效当且仅当两侧等价。仅改排符号或给少量例子不足以证明语义关系。
先认识这些词
等价 每个赋值下真值一致。
逆命题 将P→Q反转为Q→P。
逆否命题 与P→Q等价的¬Q→¬P。 04 / 先看一个完整例子 化简F=¬(p∨¬q)。用De Morgan得¬p∧¬¬q,再双否定得¬p∧q。p假q真时两式真,但单行不是证明,规则保证四行全部一致。比较p→q与q→p,p假q真时前真后假,立即推翻等价。正确反向等价式是¬q→¬p,仍排除p真q假。
一步步想清楚 一差异行为何确定不等价? 等价要求每行,一次失败就推翻。
¬(p∧q)怎样分配? 否定两侧并将合取换析取,得¬p∨¬q。
反转蕴含会保留它吗? 逆否还须否定两侧,仅逆命题通常不同。
完整推导一道题 · 01 化简嵌套否定 用等价律化简F=¬(p∧¬q),并在p真q假时求两式值。
先选择方法 先将外否定推过合取,再删双否定。
De Morgan得¬p∨¬¬q,因为否定将∧换∨。
双否定将¬¬q化为q,得¬p∨q。
p真q假时原内部p∧¬q真,F假;改写式假∨假也假。
解释最终答案 F≡¬p∨q≡p→q。样本行一致,而规则证明全行等价。
检验推理 p假时改写式无论q都真,符合原式否定假合取。
完整推导一道题 · 02 推翻诱人的反转 比较F=p→q与G=q→p,给反赋值,再写F正确等价反向式。
先选择方法 寻找一侧前件假,另一侧真前件假结论的行。
取p假q真,F因前件p假而真。
G因q真p假而假,因此两式此行不同。
反转同时否定两侧得¬q→¬p,与F同样仅在p真q假时为假。
检验推理 p=q=真时两者碰巧都真,但该一致行不能修复反例。
Leon 的进一步思考 子公式边界重要 ¬(p∨q)∧r中否定只覆盖p∨q。De Morgan改写不能改外层与r的合取。
程序副作用需另行处理 纯布尔等价不保证函数调用顺序或次数相同,逻辑假设原子已具有固定真值。
注意这个边界. p→q与q→p通常不同。逆否既反转也否定两侧。
检查自己的理解: 某赋值下F↔G真就能推出F≡G吗? 不能。等价要求每赋值下双条件都真,一行只证明局部一致。
↑ 返回知识框架 COMP2022 / 22 Leon
命题逻辑的范式 01 / 从一个故事开始 仓库检查员有一组必须全部通过的清单,每份清单允许若干替代条件。这个“每组至少一个、全部组都满足”的形状就是合取范式。换成统一形状方便算法处理,却可能重复很多内容。范式并不意味着唯一、最短或最容易读。
02 / 理解原理 否定范式只用合取、析取,并把否定放在原子前。先消去蕴含与双条件,再用 De Morgan 律把否定向内推。合取范式是若干子句的合取,每个子句是文字的析取。把析取分配到合取上可得到它,但表达式可能指数增长。单个文字也可作为子句。
这里的命题 CNF 与文法的 Chomsky 范式是不同概念。SAT 转换有时引入新变量以避免膨胀;这通常保证可满足性对应,不能直接说新旧公式在同一组变量上等价。
先认识这些词
文字 原子或单个原子的否定。
子句 文字的析取,例如 p∨¬q。
合取范式 子句的合取,每条子句都须成立。 04 / 先看一个完整例子 把 p→(q∧r) 写成 ¬p∨(q∧r),再分配得到 (¬p∨q)∧(¬p∨r)。p 假时两子句自动成立,p 真时必须 q、r 都真。式子 (p∧q)∨r 当前不是合取范式,但可改写为 (p∨r)∧(q∨r);判断当前语法形状与判断能否转换是两回事。
一步步想清楚 p 是子句吗? 是,单个文字是一文字子句。
¬(p∨q) 是否是否定范式? 不是,改为 ¬p∧¬q 将否定移到原子前。
转换一定缩短公式吗? 不一定,分配可能重复子公式并大幅增大长度。
完整推导一道题 · 01 转换带替代条件的规则 用普通二值逻辑将 (p∧q)→r 转为合取范式,不引入新变量。
先选择方法 消去蕴含,再把否定向内推。
A→B 等于 ¬A∨B,故得到 ¬(p∧q)∨r。
De Morgan 将 ¬(p∧q) 改为 ¬p∨¬q。
结合律得到一个子句 ¬p∨¬q∨r,已是合取范式。
解释最终答案 合取范式为 ¬p∨¬q∨r,仅禁止 p、q 真而 r 假。
完整推导一道题 · 02 分配两组条件 将 (p∧q)∨(r∧s) 转为合取范式,数子句,并在 p 真、q 假、r 真、s 真时求值。
先选择方法 每次分配一个合取,保留全部配对。
先得到 [p∨(r∧s)]∧[q∨(r∧s)]。
分别分配得 (p∨r)∧(p∨s)∧(q∨r)∧(q∨s)。
共有四条子句。给定赋值下因 r、s 都真,每条都真。
解释最终答案 四子句合取范式为真,与原式右边合取为真一致。
检验推理 p=r=假时 p∨r 子句假,原式两合取也都假。
Leon 的进一步思考 把合取范式读成清单 一个真文字满足所在子句,不会自动满足所有子句。在 (p∨q)∧r 中令 p 真仍须满足 r。
新变量改变比较方式 若用新变量 z 代表 p∧q,须用子句约束两者关系。保可满足性问是否存在合适 z,不是每个 z 都与原式一致。
注意这个边界. 不要把合取范式与析取范式混淆。子句不一定恰有三个文字。
检查自己的理解: ¬(p∧q) 已是否定范式吗? 不是,否定作用于复合式。改写 ¬p∨¬q 后是否定范式,也是一条子句组成的合取范式。
↑ 返回知识框架 COMP2022 / 23 Leon
逻辑后承与反模型 01 / 从一个故事开始 审查员问:只要所有前提都成立,结论就一定成立吗?一份所有前提真而结论假的记录,就足以推翻这种保证。这叫反模型。如果前提本来就相互矛盾,没有任何记录能同时满足它们,那么所有结论都会在形式上空泛成立。
02 / 理解原理 Γ 在语义上蕴涵 F,指每个满足 Γ 中全部公式的赋值也满足 F。对有限前提,可以把它们与 ¬F 合取;若不可满足,推理有效。若可满足,该赋值就是反模型。有效性不保证现实中的前提为真;某次结论碰巧为真也不证明推理有效。
肯定前件与否定后件是有效规则。肯定后件、否定前件一般无效。后承有方向;等价则要求两个方向都成立。
先认识这些词
前提 检查推理时暂时假定为真的陈述。
反模型 全部前提真而结论假的赋值。
后承 在前提的每个模型中都为真的结论。 04 / 先看一个完整例子 设 p 为文件通过验证,q 为文件被接受。p→q 与 q 不能推出 p:p 假、q 真使两个前提真而结论假,文件或许通过另一条途径被接受。若把前提 q 改成 ¬q,则可推出 ¬p;因为 p 真会与规则一起迫使 q 真,与已知 ¬q 冲突。
一步步想清楚 前提现实中为假会令推理形式无效吗? 不会,有效性考察所有前提成立时能否保真。
怎样用可满足性检查后承? 寻找前提与结论否定一起的满足赋值。
为何一个反模型就够? 后承要求前提的每个模型都成功。
完整推导一道题 · 01 连接两条蕴含 经典命题逻辑中,p→q、q→r、p 是否推出 r?
先选择方法 假设所有前提真,逐步传播其必需后果。
第三前提使 p 真。
p→q 真且 p 真,故 q 必真,否则蕴含失败。
q→r 真且 q 真,故 r 必真,不可能有反模型。
检验推理 p=q=r=真满足前提,故并非不一致前提造成的空泛结果。
完整推导一道题 · 02 检验否定前件 p→q 与 ¬p 能推出 ¬q 吗?若可行请构造反模型。
先选择方法 先使拟议结论假,再看前提是否仍成立。
要使 ¬q 假,令 q 真。
要满足 ¬p,令 p 假。
p 前件假使 p→q 真。两前提都成立,但 ¬q 失败。
解释最终答案 不能。p 假、q 真是反模型;规则没有说 p 是 q 的唯一途径。
检验推理 该赋值确实满足 p→q,因为没有真前件假结论。
运行一个完整示例 · 01 找出全部反模型 穷举两个布尔原子,检查 p→q 是否推出 p∨q。
Python 3 复制代码 下载源代码 ↓ 长代码行可左右滚动。复制或下载会保留原始代码。
from itertools import product
rows = []
for p , q in product ([ False , True ], repeat = 2 ):
premise = ( not p ) or q
conclusion = q or p
if premise and not conclusion :
rows . append (( p , q ))
print ( "Countermodels:" , rows )
assert rows == [( False , False )]
在本地运行 python logical-consequence-entailment-countermodels.py 预期输出 Countermodels: [(False, False)] 按执行顺序理解 枚举(假,假)、(假,真)、(真,假)、(真,真)。
在(假,假)下蕴含真,而 p∨q 假。
其他三行都不是反模型;保存的一个值对足以推翻后承。
逐步读懂代码 product 生成 p 与 q 的全部四种组合。for 循环把每对值分别赋给两个变量。Python 的 not 表示否定,or 表示包含“两者都真”的析取,因此 (not p) or q 表示蕴含。
if 只保留前提真而结论假的行。append 把该值对加到列表,print 显示完成的列表,assert 检查预期结果。这个有限穷举只检验此推理;原子更多时所需行也更多。
Leon 的进一步思考 利用结论指导寻找 反驳 Γ⊨p∨q 时先令 p=q=假,这是结论失败的唯一方式,再检查前提能否仍真。
区分一致性与有效性 在把 p 与 ¬p 推出的结论当作有用知识前,先检验前提是否有模型。逻辑有效性本身不回答这个不同问题。
注意这个边界. 不要只检查结论为真的赋值。反模型必须令全部前提真、结论假。
检查自己的理解: p 与 ¬p 能推出 q 吗? 能,形式语义上是空泛成立:没有赋值同时满足两个前提。这不代表这些前提一致或有用。
↑ 返回知识框架 COMP2022 / 24 Leon
谓词、量词与作用域 01 / 从一个故事开始 每位学徒都有导师,与有一位导师指导所有学徒,不是同一句话。第一句允许不同学徒选择不同导师,第二句要求同一人胜任。要判断真假,必须说明讨论哪些对象,以及指导关系具体有哪些。符号能帮助我们保留这些容易被日常语言隐藏的差别。
02 / 理解原理 谓词逻辑让变量在明确的非空论域中取对象。∀ 表示每个对象,∃ 表示存在见证。“所有 A 都是 B”写为 ∀x(A(x)→B(x));“有些 A 是 B”写为 ∃x(A(x)∧B(x))。不同量词的顺序决定后面的见证是否可依赖前面的对象。否定量词时交换 ∀ 与 ∃,并否定其内部公式。
量词有作用域,作用域外的同名变量不因此被约束。自由变量需要额外赋值。跨公式移动量词须检查该变量是否在另一部分自由出现;必要时先重命名约束变量,避免捕获。
先认识这些词
论域 变量可以指向的非空对象集合。
见证 使存在陈述为真的对象。
作用域 受某个量词或联结词管辖的公式部分。 04 / 先看一个完整例子 论域为 Ada 与 Ben,且只有两条关系:Ada 指导 Ben,Ben 指导 Ada。每个人都有导师,所以 ∀x∃y M(x,y) 真;无人指导自己,所以不存在指导所有人的同一个导师,∃y∀x M(x,y) 假。
第一句的否定为 ∃x∀y¬M(x,y),即有人完全没有导师。“并非每位学徒都获认证”是 ∃x(Apprentice(x)∧¬Certified(x));仅写 ∃x¬Certified(x) 可能找到了非学徒。
一步步想清楚 ∀x∃y 的见证可不同吗? 可以,每次选定 x 后,合适 y 可依赖它。
怎样否定 ∃xP(x)? 写为 ∀x¬P(x),每个候选对象都不满足性质。
所有 A 都是 B 为何用蕴含? 只要求 A 对象通过 B 检查,非 A 对象不受此要求。
能交换这两个量词而不改变命题吗? 一般不能。给定关系让“全称—存在”为真、“存在—全称”为假,是二者等价这一主张的反模型。
完整推导一道题 · 01 会改变的见证 论域 {1,2,3},R(x,y) 表示 x≠y。求 ∀x∃yR(x,y) 与 ∃y∀xR(x,y) 的真假。
先选择方法 第一式给每个 x 找见证,第二式用全部 x 检验固定 y。
x=1 选 y=2;x=2 选 y=1;x=3 选 y=1。每个 x 都有不同伙伴。
对任何固定 y,全称 x 都包括 x=y。
x=y 时 R 假,故没有一个 y 能通过全部三个 x 检查。
解释最终答案 第一式真,第二式假,交换不同种类量词会改变意义。
检验推理 不等有序对有六个,三个对角对缺失;每行有见证,每列有失败。
完整推导一道题 · 02 否定全称类别规则 学生为 {A,B,C},Pass(A) 真、Pass(B) 假、Pass(C) 真。翻译并判断“并非每位学生通过”。假设论域只有学生。
先选择方法 否定全称量词,再找具体失败学生。
每位学生通过是 ∀xPass(x),论域已将 x 限制为学生。
否定得到 ¬∀xPass(x)≡∃x¬Pass(x)。
选 x=B,Pass(B) 假,故 ¬Pass(B) 真,B 是所需见证。
解释最终答案 陈述为真,表示至少一人失败,不表示所有人都失败。
检验推理 A、C 通过,故更强的 ∀x¬Pass(x) 为假。
完整推导一道题 · 03 否定并检验量词命题 使用代码中的三名学生、两名导师。否定“每个学生都有导师”,再判断删除 (Bo,Noah) 后否定命题是否成立。
先选择方法 把否定依次推进各量词,再寻找具体见证。
¬∀x∃yR(x,y) 变成 ∃x¬∃yR(x,y)。
¬∃y 变成 ∀y¬,得到 ∃x∀y¬R(x,y)。
删除后,R(Bo,Ivy)、R(Bo,Noah) 都为假,选择 x=Bo。
检验推理 删除前每个学生的见证列表非空,因此否定命题为假。
运行一个完整示例 · 01 在有限模型中寻找见证与反例 社团的每个学生都有导师。米娜听完,以为存在一位导师指导所有学生。一个小表就推翻了这个想法:Ana、Cy 跟 Ivy,Bo 跟 Noah。每个学生都有人指导,却没有一个导师覆盖三人。米娜用嵌套循环把两个量词的顺序具体展示出来。
Python 3 复制代码 下载源代码 ↓ 长代码行可左右滚动。复制或下载会保留原始代码。
students = [ "Ana" , "Bo" , "Cy" ]
mentors = [ "Ivy" , "Noah" ]
relation = {( "Ana" , "Ivy" ), ( "Bo" , "Noah" ), ( "Cy" , "Ivy" )}
def inspect ( students , mentors , relation ):
witnesses = { x : [ y for y in mentors if ( x , y ) in relation ] for x in students }
every_has_someone = all ( witnesses [ x ] for x in students )
shared = [ y for y in mentors if all (( x , y ) in relation for x in students )]
uncovered = [ x for x in students if all (( x , y ) not in relation for y in mentors )]
assert bool ( uncovered ) == ( not every_has_someone )
return witnesses , every_has_someone , shared , uncovered
witnesses , every , shared , uncovered = inspect ( students , mentors , relation )
print ( "witnesses:" , witnesses )
print ( "every student has a mentor:" , every )
print ( "one mentor for everybody:" , bool ( shared ))
assert every and not shared
broken = relation - {( "Bo" , "Noah" )}
print ( "counterexample after removal:" , inspect ( students , mentors , broken )[ 3 ])
assert inspect ([], mentors , relation )[ 1 ] is True
assert inspect ( students , [], relation )[ 1 ] is False
在本地运行 python predicate-logic-finite-witness-search.py 预期输出 witnesses: {'Ana': ['Ivy'], 'Bo': ['Noah'], 'Cy': ['Ivy']}
every student has a mentor: True
one mentor for everybody: False
counterexample after removal: ['Bo']
按执行顺序理解 为每位学生建立见证列表;内层存在量词可以为不同外层学生选择不同导师。
寻找共同导师时反过来:先选一个导师,再要求他覆盖每位学生。
若某学生对所有候选导师都不满足关系,他就是未被覆盖者;这会构造否定命题的见证,而不只是打印 False。
检查空集合情形。没有学生时全称命题为真;有学生却没有导师时,原命题为假。
逐步读懂代码 设 S 为学生集合、M 为导师集合,R(x,y) 表示 y 指导 x。第一个命题是“对每个 x∈S,存在 y∈M,使 R(x,y)”;第二个是“存在 y∈M,对每个 x∈S 都有 R(x,y)”。共同见证能证明第二个,进而证明第一个;各自的见证只能证明第一个。
否定第一个命题得到:“存在 x∈S,使每个 y∈M 都不满足 R(x,y)”。删掉 Bo–Noah 后,Bo 就成为这个反例。|S| 名学生、|M| 名导师的直接检查需要 O(|S||M|) 次关系查询,这里假定集合查询平均 O(1)。
程序检查的是一个指定的有限解释。在一张表上成立,并不证明公式在所有解释中都有效,也不能解决任意一阶逻辑有效性。论域假设应写在题目中,不能遇到不想要的结果后再临时改变空集规则。
Leon 的进一步思考 展开有限论域检验含义 论域 {1,2} 上,∀xP(x) 等于 P(1)∧P(2),∃xP(x) 等于 P(1)∨P(2),将量词连到熟悉的命题运算。
检查非空论域中的空类别 若没有对象是龙,∀x(Dragon(x)→Blue(x)) 为真。它不表示有龙;存在性须另加 ∃xDragon(x)。
注意这个边界. 所有 A 都是 B 不是 ∀x(A(x)∧B(x))。后者要求论域每个对象同时是 A 与 B。
检查自己的理解: (∀x P(x))∧Q(x) 中 Q 的 x 被前面量词约束了吗? 没有,Q(x) 在该量词括号之外。它的 x 是自由变量,需要赋值。
↑ 返回知识框架 继续探索 故事、概念讲解和推导例题由 Leon 原创编写。课程代号标识独立学习路径。参考资料属于各自作者。