老侦探王振东接过一桩悬案:富商被害,嫌疑人张三是唯一的焦点。王振东没有急着定罪,反而先假设张三无罪——然后,他在证物堆里找到了矛盾:张三声称案发时在家睡觉,可监控清楚地拍到他当晚出现在案发现场。矛盾出现了,无罪假设崩塌,定罪成立。这套“先假设无罪、再找矛盾”的破案心法,正是数理逻辑中归结原理(Resolution)的底层思想。本文要讲的,就是如何把这种侦探思维翻译成一套机器可执行的推理规则:先把千头万绪的案情整理成统一格式的“证词笔录”,再由一台“逻辑侦探”用反证法反复比对,找出矛盾,最终一锤定音。归结原理是自动定理证明的引擎,也是Prolog逻辑编程语言的心脏。掌握了它,你就掌握了让机器自己“想明白一件事”的底层秘密。
理解归结原理是通往自动定理证明、SMT求解器与逻辑编程语言(Prolog)的钥匙。对AI从业者而言,它正是构建推理引擎、验证系统与知识库问答系统的核心功底。
可视化演示
展示归结原理通过合取范式转换、互补文字消解与反证法推导空子句,实现自动定理证明的完整流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
合取范式CNF转换 将逻辑公式转换为子句合取形式,每个子句为文字析取 消除蕴含→否定内移→分配律展开 (P→Q)∧(Q→R)∧P∧¬R 转换后得到4个子句作为归结输入
归结思想起源
老侦探王振东的第一课,是办案室墙上的八字箴言:“先假设无罪,再找矛盾。”这不是消极待命,而是最高效的进攻——只要找到一个矛盾,整个案件就推进了一大步。归结原理的哲学,正是把这句箴言搬进了逻辑世界。它不直接证明“张三有罪”,而是假设“张三无罪”,然后寻找逻辑上的不可能,让无罪论自己崩溃。
这个“找矛盾”的过程,在数理逻辑里有一个精确的名号——反证法(Proof by Contradiction)。归结原理是1965年由逻辑学家鲁滨逊(J. Alan Robinson)提出的,他用一条极其简单的规则证明了:任何不可满足的子句集,都能通过不断“消解矛盾”推导出空子句,这就是归结的完备性定理。换句话讲:只要案件确实有矛盾,这台逻辑侦探机器就一定有办法找到它。
一句话回扣:归结原理不是那种正面硬刚的莽夫,而是像王振东一样,把“假设无罪”挂在嘴边,默默等待矛盾自己跳出来。
- \(\Gamma\) 是什么代表前提集合,即侦探手里已有的全部线索——已知的事实、规则与假设。
- \(\models\) 的含义称为“逻辑蕴含”,读作“必然推出”。它在说无论世界如何取值,只要 \(\Gamma\) 成立,\(\varphi\) 就必定成立。
- 否定结论 \(\neg\varphi\)把要证明的结论反转,相当于“假设张三无罪”——这是反证法的起点。
- 不可满足合并后没有任何一种“世界真相”能让全部子句同时成立,矛盾爆发,反证成功。
子句与范式
王振东有个习惯:每到一个案发现场,先把目击证人的口述整理成标准笔录——每人一页,每页一行,字迹统一,句式固定。杂乱无章的破案线索毫无效率,只有统一格式后才能快速交叉比对。归结原理也一样,它要求所有逻辑公式先完成一次“标准化”:变成合取范式(CNF,Conjunctive Normal Form)。
CNF是一种极其刻板的规范格式:整个公式是所有简单子句的“且”(\(\land\))组合,每个子句内部则是文字的“或”(\(\lor\))组合。一个文字是原子命题或其否定,一个子句就是若干文字的析取。为了把五花八门的公式(蕴含、等价、各种括号嵌套)塞进这个模具,需要三个标准动作:消除蕴含、内移否定词、斯柯伦化(Skolemization)。其中消除蕴含用的公式最常用:
回到侦探视角:王振东的“标准笔录”就是 CNF。每个目击者一页纸,每行一个子句,语言干净统一;后续无论多少线索涌进来,都能在同一张比对桌上展开交叉验证。
- 蕴含的本质\(P \rightarrow Q\) 唯一为假的情形是“\(P\) 真且 \(Q\) 假”。把它翻译成“或”形式,条件就一目了然。
- 否定前件\(\neg P\) 承担了“如果 \(P\) 没发生会怎样”的分支,它与其他文字用“或”连接。
- 等价的含义两条式子在任何真假组合下取值完全相同,因此可以无损失地互相替换。
- 斯柯伦化补充当公式中出现存在量词(\(\exists x\),意为“存在某个 \(x\)”)时,用一个新常元替换它——好比把“现场有个神秘人”记成“神秘人编号X7”,后续比对就有名有姓了。
归结消解规则
有了统一格式的笔录,王振东开始真正的“侦破动作”:把他认为可能矛盾的两份笔录放在桌上,逐句比对。他发现第一份说“张三在卧室或者在大厅”,第二份说“张三不在卧室或者在看电视”——两句中“张三在卧室”和“张三不在卧室”恰好在打架!老王果断划掉这个矛盾点,把剩下的信息拼成一条新线索:“张三在大厅或在看电视”。
这个“划掉矛盾、拼接剩余”的规则,就是归结消解规则(Resolution Rule)。它依赖的关键概念是互补文字对:一个文字和它的否定正好同时出现在两条子句中。归结后产生的新子句叫归结式;若某次归结让子句彻底空了——两边各只剩一个互相否定的文字,抵消后空无一人——就得到了空子句,记为 \(\square\),它是逻辑体系中最致命的“矛盾铁证”。
这便是侦探工作的最小单元:检出矛盾、剥离矛盾、拼接新证。一次归结不一定立刻破案,但每归约一次,证词总量就在减少,离真相就进一步。
- 两条父子句\((L \vee A)\) 与 \((\neg L \vee B)\) 是两个待比对的子句,类似两份待对质的证词。
- 识别互补对左侧子句里的 \(L\) 与右侧子句里的 \(\neg L\) 互相否定,构成矛盾点。
- 产出归结式矛盾点被划去,其余文字 \(A\) 与 \(B\) 取并集形成新子句。
- 空子句特例当 \(A\) 与 \(B\) 都为空时,得到 \(\square\),表示彻底矛盾——反证法里的“定罪铁证”。
合一算法
王振东遇到一个新麻烦:两名目击者描述同一个人时用了不同的说法——一个人说“那个穿风衣的黑衣人”,另一个说“戴金表的高个子”。老王敏锐地意识到他们说的是同一个人,但要在卷宗里把这两种描述对齐,才能继续比对矛盾。在谓词逻辑的归结中,这个“对齐不同说辞”的动作,就是合一算法(Unification)。
命题逻辑中文字只有真假之分,而谓词逻辑中的文字含有变量、函数和常量——比如 \(P(f(x), y)\) 与 \(P(f(a), z)\) 看起来不完全相同,但可以通过一套替换让它们变得一样:把 \(x\) 换成常量 \(a\),把 \(y\) 换成变量 \(z\)。这套替换记作 \(\{x \mapsto a,\ y \mapsto z\}\)。找出“最一般”的替换(即不额外限制任何变量自由度),叫作最一般合一子(MGU,Most General Unifier)。合一算法递归地比对两项的结构:常量对常量、函数对函数、变量则绑定为另一项,同时要检查“变量不能出现在自身内部”(防止 \(x\) 绑定 \(f(x)\) 这类死循环)。
对老王侦探而言,合一算法就是一名出色的身份比对员:他能一眼认出“黑衣风衣男”就是“戴金表的高个子”,让两条看似无关的证词在逻辑上撞出矛盾火花。没有合一,谓词逻辑的归结寸步难行。
- 两个待合一文字\(P(f(x), y)\) 与 \(P(f(a), z)\),谓词相同(都是 \(P\)),但参数结构有待统一。
- 逐参递归比对先比第一个参数 \(f(x)\) 与 \(f(a)\)——函数 \(f\) 相同,再递归比 \(x\) 与 \(a\),\(x\) 是变量,绑定为 \(a\)。
- 绑定第二个变量继续比 \(y\) 与 \(z\),两个都是自由变量,可令 \(y\) 绑定 \(z\)(或反向),保留自由度取 \(y \mapsto z\)。
- 组合成 MGU所有绑定合并为完整替换 \(\{x \mapsto a,\ y \mapsto z\}\),此时两个文字结构完全一致,可以进入归结。
归结反演
单点矛盾找到后,王振东还会做最后一次全景复盘——把整场推理串成一条完整的“定罪链”:从无罪假设出发,经过三步两步归结,每一次矛盾消解都像多米诺骨牌一样倒下,最终撞出一个彻底的死局。这个从假设到铁证的完整流程,就是归结反演(Resolution Refutation),也叫反驳证明。
归结反演有五步固定走位:第一步,把所有前提公式转成 CNF 子句集 \(S\);第二步,把要证明的结论取否定,也转成子句,并入 \(S\);第三步,在这组扩大的子句集里反复应用归结消解规则;第四步,一旦得到空子句 \(\square\),即宣告“矛盾成立”;第五步,由此反推原结论必然为真。整个过程若能画成一棵以 \(\square\) 为根的推导树,就称为反驳树(Refutation Tree)——每个分叉代表一次归结,树根是最终矛盾,树干则是承前启后的归结式。
所以归结反演是一场完美的“审判流程”:假设无罪(否定结论)→ 提交证据(加入子句集)→ 交叉质证(反复归结)→ 矛盾爆发(推出空子句)→ 判处有罪(结论成立)。这套流程已经被无数定理证明器自动执行了半个多世纪。
- 扩充子句集把结论的否定 \(\neg\phi\) 转成子句并加入前提子句集 \(S\),相当于侦探把“无罪假设”写进卷宗。
- 归结推导符号\(\vdash_{R}\) 表示“通过有限次归结步骤可以推出”,是一种机械可验证的推导关系。
- 得到空子句\(\square\) 代表推导链走到了彻底的逻辑死胡同——子句集不可满足,假设崩塌。
- 结论必真既然“前提 + 结论否定”是个矛盾,那么只要前提 \(S\) 为真,结论 \(\phi\) 就不得不为真。
Prolog应用
王振东退休那天,把整本办案手册交给了徒弟——一台名叫 Prolog 的自动侦探机器人。手册里的每条规则都是“如果……那么……”的规范陈述,而机器人翻着手册替人断案的机制,正是归结原理的实战形态。Prolog(Programming in Logic)是一种逻辑编程语言:程序员不写“怎么算”,只写“事实是什么”,剩下的查案交给机器。
Prolog 内部使用的推理引擎叫作 SLD 归结——它是归结原理的一种高效特化:每个规则都是霍恩子句(Horn Clause),形式为“结论 ← 一组前提”,翻译成逻辑公式就是“结论或各前提的否定之或”。推导时,机器人采用线性归结(沿一条链推进)加深度优先搜索的方式,不断把查询目标与规则头部合一,一旦某条路径撞上矛盾就回溯换路。你输入一个查询“凶手是不是张三?”,Prolog 不是直接翻答案,而是对“张三不是凶手”这个假设发起一场归结反演。
在王振东的比喻里,Prolog 就是一台不知疲倦的年轻侦探:它严格照着办案手册的每一条规则线性追查,走到死路就退回去换一条,始终在归结与回溯中寻找那个致命矛盾。归结论证了 Prolog 的逻辑完备性,也成就了专家系统与演绎数据库的黄金年代。
- 规则的方向\(A \leftarrow B_1 \land B_2\) 表示“若 \(B_1\) 且 \(B_2\) 成立,则 \(A\) 成立”,这是 Prolog 的书写惯例。
- 改写为子句把蕴含消除,等价化为 “\(A\) 或非 \(B_1\) 或非 \(B_2\)”——它正好是一个三文字的子句。
- SLD 的特化每个子句至多一个正文字(霍恩子句),选择规则通常取查询中的最左文字进行归结,这就是"SLD"中 S(选择)与 D(限定)的含义。
策略与优化
徒弟侦探毕竟没有师父的经验,面对堆积如山的证词卷一通乱查,效率低得令人发指。王振东于是写下了一本策略手册,教徒弟如何少走弯路。归结虽然完备,但朴素地枚举所有子句两两配对会产生海量无用的归结式——必须引入策略裁剪搜索空间。
第一条策略是删除策略:把不会影响矛盾发现的垃圾子句直接扔进碎纸机——比如含互补文字对的永真子句(\(P \vee \neg P\),任何情况下都成立,对找矛盾毫无贡献),以及被其他子句“包含”的冗余子句(信息量更少、完全被覆盖的线索)。第二条是线性归结:要求每一步归结的参与者中,至少有一个是刚产出的归结式,逼迫推导沿一条主线纵深推进,而不是在整张网上四面开花。第三条是宽度优先与启发式选择:优先挑选文字数目少的子句参与归结,或优先处理猜测最容易产出空子句的配对,把计算资源花在刀刃上。
策略手册的精髓,正是老侦探的经验之谈:破案拼的不只是“能不能找到矛盾”,更是“多久能找到矛盾”。删除冗余线索、集中兵力沿主线深挖、优先盯住可疑对象——这些策略让归结从理论上的完备,走向工程上的高效。
- 包含关系\(C_1 \subseteq C_2\) 意味着 \(C_2\) 拥有 \(C_1\) 的全部信息且只多不少,多出的部分不增加新力量。
- 蕴含的保证若 \(C_1\) 成立则 \(C_2\) 必然成立,因此 \(C_2\) 不会比 \(C_1\) 带来更多约束。
- 删除冗余为缩小搜索空间,直接删去 \(C_2\),保持子句集精简,但不会破坏对矛盾的检测能力。
局限与展望
即便有策略手册,王振东也不得不承认:有些案子是“人力不可及”的。当子句数量增长到一定程度,两两配对的组合数会呈爆炸式增长——这就是归结原理的指数爆炸(Combinatorial Explosion)。一台侦探机器人就算穷尽所有配对,也可能在有限时间内找不到矛盾(尽管矛盾一定存在)。更根本的局限在于,一阶逻辑本身是不可判定的:归结能保证“有矛盾必有发现”,却无法保证“没有矛盾时及时宣布无罪”。
为了在真实工程中对抗爆炸,研究者们走出了两条路。其一是语义归结:利用解释(模型)信息剪枝——让侦探先根据经验排除明显不可能的配对方向,再专心找矛盾;其二是把归结与布尔可满足性求解(SAT/SMT)结合,诞生了今天工业界广泛使用的SMT 求解器(如 Z3),它在命题层用高效的 SAT 算法冲锋陷阵,在理论层用一阶推理兜底,已然成为软件验证、程序分析领域的标准武器。
故事讲到最后,王振东把手册合上,望着窗外的夜色感叹:再神的侦探也有极限,但聪明的侦探懂得在正确的地方使用正确的工具。归结原理是逻辑推理的基石之一,它在一个世纪里催生了自动定理证明、Prolog、SMT 求解器乃至今天以“逻辑推理”为卖点的 AI 系统。
- 规模度量\(n\) 代表初始子句集中子句的数量,是案件复杂度的标尺。
- 指数增长\(2^n\) 表示最坏情况下可供尝试的归结配对组合数——每多一条子句,可能性就翻一倍。
- 大O记号\(T(n) = O(2^n)\) 说明运行时间的增长趋势是指数级;当 \(n\) 稍大时,任何机器都无能为力。
AI 应用场景
自动定理证明器(Vampire / E Prover)
阶段:推理引擎构建
解决的问题:在数学定理证明与软件正确性验证中,人工推理既慢又不可靠。传统方式依赖数学家手写证明,且难以验证每一步的机械正确性。基于归结原理的自动定理证明器把“找矛盾”这件事全权委托给机器:输入一组公理与待证命题,引擎自动完成 CNF 转换、合一与归结反演,一小时能完成人脑数周的工作量。
具体案例:在航空嵌入式软件的验证中,工程师使用 Vampire 自动证明器验证数据流模块的若干安全性引理。工程师将程序行为建模为一阶逻辑公式,把“无空指针解引用”等安全性质取否定后交给证明器;证明器经过数十轮归结推导出空子句,确认性质成立,避免了飞行控制系统上的致命缺陷。
Prolog 逻辑编程与专家系统
阶段:知识表示与推断执行
解决的问题:传统命令式语言要求程序员完整描述一步步“如何做”,这对专家规则类问题(诊断、配置、法律咨询)既笨拙又难维护。Prolog 的解决方案是只写“是什么”——事实与规则,执行时由 SLD 归结自动完成查询求值。知识库更新只需增删规则,无需改代码。
具体案例:某保险公司用 Prolog 构建车险核保专家系统:规则库存放“年龄<25 且事故次数>2 → 高风险”等上百条霍恩子句规则,核保员输入客户信息查询“可承保类别”,Prolog 在毫秒级内通过归结与回溯返回结论,同时还能解释推理路径——这个可解释性让监管审核极为满意。
SMT 求解器中的混合求解
阶段:约束求解与程序验证
解决的问题:单纯使用归结处理现实规模问题会遭遇组合爆炸。现代 SMT 求解器(如 Z3)把命题层的布尔冲突分析与理论层的等价推理结合:SAT 求解器快速分析布尔骨架,每次发现可能矛盾时,理论求解器(内部大量使用合一与归结类算法)验证理论约束是否兼容。这种“分层协作”让验证能力扩展到百万级变量的工业代码。
具体案例:在数据库存储引擎的开发中,工程师用 Z3 自动验证并发的日志回收协议是否可能死锁。系统把状态机建模为一阶逻辑公式,Z3 通过合一千字节级的约束集在数秒内报告“存在一个可到达的死锁状态”,并给出反例路径,帮助团队在发布前修复了 bug。
Python 演示
# -*- coding: utf-8 -*-"""迷你归结证明器——侦探办案手册的 Python 实现"""from itertools import combinations def complement(literal): """求文字的补:P 与 ~P 互为否定""" return literal[1:] if literal.startswith("~") else "~" + literal def resolve(c1, c2): """对两个子句尝试一次归结,返回所有可能的归结式""" results = [] for a in c1: for b in c2: if a == complement(b): # 互补对抵消,两侧剩余文字取并集 resolvent = (set(c1) - {a}) | (set(c2) - {b}) results.append(resolvent) return results def prove(clauses, goal): """反证法:把目标的否定加入子句集,推出空子句则得证""" kb = [set(c) for c in clauses] kb.append({complement(goal)}) seen = set() for c in kb: seen.add(frozenset(c)) while True: new_set = set() for i, j in combinations(range(len(kb)), 2): for r in resolve(kb[i], kb[j]): if not r: return True rf = frozenset(r) if rf not in seen: seen.add(rf) new_set.add(rf) if not new_set: return False kb.extend([set(c) for c in new_set]) if __name__ == "__main__": print("=== 案例1:假言推理 ===") print("已知 {P, ~P∨Q},求证 Q") kb1 = [{"P"}, {"~P", "Q"}] print("证明成功!" if prove(kb1, "Q") else "无法证明!") print("\n=== 案例2:传递律 ===") print("已知 {~P∨Q, ~Q∨R},求证 P→R") kb2 = [{"~P", "Q"}, {"~Q", "R"}] ok = prove(kb2, "~P∨R") print("证明成功!" if ok else "无法证明!")
def complement(literal)判定文字是否互为否定,这是归结规则识别“互补文字对”的唯一依据。if a == complement(b)内层循环找出两条子句中的矛盾点,一旦命中就触发抵消。resolvent = (set(c1) - {a}) | (set(c2) - {b})抵消互补对,把剩余文字并入新子句,对应归结式 \(A \vee B\)。if not r: return True归结式为空即得到空子句 \(\square\),矛盾爆发,结论得证。rf not in seen用集合记录历史子句,防止重复产生同一归结式,这是工程版的“删除策略”。kb.append({complement(goal)})反证法的起点:把结论的否定加入子句集,如同侦探写下“假设无罪”。for i, j in combinations(range(len(kb)), 2)两两枚举子句配对,等价于侦探把证词两两放上比对桌。
常见误区
误区我以为归结原理就是反证法,只要用了归结原理就等于用了反证法,两个概念是一回事。
正解反证法是宏观的证明策略(假设结论为假,期望由此推出矛盾),归结是微观的推理规则(合并两条子句消去互补文字对)。一个案件里,反证法是“先假设无罪”的办案方针,归结是“比对证词找矛盾”的具体招式。通常我们把二者组合成“归结反演”:用反证法搭框架,用归结消解填血肉。
为何常见:教科书总把“归结反演”作为一个整体名词教学,导致初学者误以为归纳中只存在一种方法,忽略了二者的层次差异。
误区把 \(P \rightarrow Q\) 转成 \(\neg P \vee Q\)、或者用斯柯伦化消去存在量词后,总觉得公式含义“变了”,怀疑推理结果是否可靠。
正解CNF 转换分两类:逻辑等价变换(如蕴含消除)严格保持真值,两式对所有赋值同真假;斯柯伦化则是“保满足性”变换——它不保证两式等价,但保证“原公式可满足当且仅当新公式可满足”。由于归结反演关心的只是“子句集是否不可满足”,保满足性就足够支撑推理结论了。这好比笔录改写可以调整措辞,但不能改变目击者证词的核心事实。
为何常见:教科书强调“转换步骤较多,容易出错”,学生便潜意识担心每一步都在走样;再加上斯柯伦化引入了新常量,更让人疑心“多出来的东西”是否篡改了原意。
误区我在命题逻辑里练熟了归结,到了谓词逻辑就直接拿 \(P(x)\) 和 \(\neg P(y)\) 去抵消,结果总是不对,还以为是归结规则失效了。
正解谓词逻辑中,两个文字表面不同并不代表不能归结,关键在于它们能否通过替换变成互补对。\(P(x)\) 和 \(\neg P(y)\) 只要令 \(x\) 与 \(y\) 绑定为同一个项,就是互补;而 \(P(x)\) 和 \(\neg P(f(x))\) 因陷入循环无法合一,才真正不能归结。合一算法是谓词逻辑归结的闸门——先把身份确认好,再谈矛盾碰撞。
为何常见:命题逻辑的教学遮蔽了变量维度,初学者默认文字一一对应;遇到带变量的谓词时,仍机械套用“找相同”的直觉,忽略了替换这一中间层。
误区既然归结是完备的、机器是强大的,那么任何逻辑问题丢给它都能在有限时间内给出“对”或“错”的结论。
正解命题逻辑的归结确实可判定(一定能停止),但一阶逻辑整体不可判定。归结的完备性说的是“只要子句集不可满足,就存在有限步骤得到空子句”;反过来,如果子句集可满足,归结过程可能永远跑不出结果。这好比侦探可以保证“有矛盾一定能破案”,却无法保证“查了三天没发现矛盾,就说明嫌疑人一定无罪”。
为何常见:课程强调完备性时,学生很容易把“完备”误读为“万能”;再加上现代求解器在小规模数据上极快,进一步加深了“归结什么都能解”的印象。
面试题
Q1. 归结原理(Resolution)是由哪位学者在 1965 年正式提出的?
- A.哥德尔
- B.鲁滨逊← 正确答案
- C.图灵
- D.香农
答案:B。J. Alan Robinson(鲁滨逊)在 1965 年提出归结原理并证明了它的完备性。哥德尔证明了不完备定理,图灵提出图灵机模型,香农创立信息论。这道题考的是归结原理的“归属”——它属于自动定理证明的奠基时刻。
Q2. 两条子句能够进行归结消解的前提是:它们之间存在什么?
- A.包含完全相同的文字
- B.包含一对互补文字← 正确答案
- C.至少包含三个共同文字
- D.其中一条是空子句
答案:B。归结规则要求两个子句中各有一个文字互为否定(如 \(L\) 与 \(\neg L\)),这对互补文字被抵消后,剩余部分拼接成归结式。相同文字不会产生矛盾,空子句不是参与归结的前提。这正像侦探比对证词,只有“矛盾点”才能触发侦查新线索。
Q3. 将蕴含式 \(P \rightarrow Q\) 转换为合取范式中的子句,正确结果是?
- A.\(P \vee Q\)
- B.\(\neg P \vee Q\)← 正确答案
- C.\(\neg P \wedge Q\)
- D.\(P \vee \neg Q\)
答案:B。蕴含消除规则是 \(P \rightarrow Q \equiv \neg P \vee Q\)。它的含义是“\(P \rightarrow Q\) 唯一为假的情形是 \(P\) 真 \(Q\) 假”,所以否定前件或保留后件就覆盖了所有为真的行。选项 A 保留了前件、C 用了合取、D 翻转了符号,都不符合等价式。
Q4. 单元归结中,子句 \(\{P\}\) 与 \(\{\neg P \vee Q\}\) 的归结式是?
- A.\(\{P\}\)
- B.\(\{Q\}\)← 正确答案
- C.\(\{\neg P\}\)
- D.\(\{P, \neg P\}\)
答案:B。左边子句是单文字 \(P\),右边子句中 \(\neg P\) 与它互补,消去后仅剩 \(Q\),归结式为 \(\{Q\}\)。这正如侦探把“张三在卧室”与“张三不在卧室或在看电视”并置,划掉冲突后得到“在看电视”。其他选项都没有正确执行“互补抵消+剩余拼接”。
Q5. 合一问题 \(P(x, f(y))\) 与 \(P(a, f(b))\) 的最一般合一子(MGU)是什么?
- A.\(\{x \mapsto a\}\)
- B.\(\{y \mapsto b\}\)
- C.\(\{x \mapsto a,\ y \mapsto b\}\)← 正确答案
- D.\(\{x \mapsto a,\ f(y) \mapsto f(b)\}\)
答案:C。合一算法逐参比对:第一个参数 \(x\) 与 \(a\) 结合为 \(x \mapsto a\);第二个参数 \(f(y)\) 与 \(f(b)\) 先比函数 \(f\) 相同,再令 \(y \mapsto b\)。合并两处替换得到 \(\{x \mapsto a, y \mapsto b\}\)。选项 A、B 都只完成了一半,D 的错误在于替换的目标只能是变量而不能是函数项。
Q6. 在归结反演中,把结论 \(\varphi\) 的否定加入子句集并反复归结后,出现什么结果即证明 \(\varphi\) 成立?
- A.得到任意一个单元子句
- B.得到空子句 \(\square\)← 正确答案
- C.重新得到原结论 \(\varphi\)
- D.子句集规模不再增长
答案:B。空子句 \(\square\) 表示推导出了彻底的矛盾,说明“前提 + 否定结论”不可满足,反证法由此宣告结论成立。单元子句只表示单条线索,规模不再增长只能说明搜索穷尽,二者都不能作为定罪铁证。
Q7. Prolog 语言执行查询时使用的归结策略是?
- A.全局宽度优先归结
- B.SLD 归结(线性 + 深度优先回溯)← 正确答案
- C.随机挑选子句归结
- D.仅使用单元归结
答案:B。Prolog 采用 SLD 归结:线性归结选一条主线推进,每次选查询中最左文字进行合一,路径失败则回溯换路。宽度优先全局归结理论上完备但实际开销太大,随机与单元归结均非 Prolog 的机制。
Q8. 关于将一阶逻辑公式转换为 CNF 子句集的过程,下列说法正确的有?
- A.蕴含式 \(P \rightarrow Q\) 可替换为 \(\neg P \vee Q\)← 正确答案
- B.否定词通过德摩根律向内移动,如 \(\neg(P \wedge Q) \Rightarrow \neg P \vee \neg Q\)← 正确答案
- C.存在量词通过斯柯伦化引入新常元或新函数来消去← 正确答案
- D.CNF 转换完成后公式的真值已经改变,只能用于反证
答案:ABC。A、B 是标准的逻辑等价变换,严格保持真值;C 是斯柯伦化的定义,存在量词在无依赖时引入新常量、在依赖全称量词时引入新函数;D 错误——等价变换保持真值,斯柯伦化保持“可满足性”,而归结反演恰恰只需要可满足性判断,因此推理依然可靠。
Q9. 关于归结原理的性质与边界,下列说法正确的有?
- A.一阶逻辑归结是半可判定的:子句集不可满足时必有归结反驳,可满足时可能不终止← 正确答案
- B.归结策略的优劣影响搜索效率,但不改变归结的完备性← 正确答案
- C.语义归结通过引入模型/解释信息来裁剪搜索空间← 正确答案
- D.删除永真子句(如 \(P \vee \neg P\))会破坏归结的完备性
答案:ABC。A 正确描述了一阶逻辑的半可判定本质;B 正确——完备性由归结规则本身保证,策略只是效率问题;C 是语义归结的核心思想;D 错误——永真子句对寻找矛盾毫无贡献,删除它不会影响“能否推出空子句”,因此保持完备性,这是删除策略的理论依据。
Q10. 以下哪些做法能有效缓解归结原理的搜索爆炸问题?
- A.删除被其他子句包含的冗余子句← 正确答案
- B.采用线性归结使推导沿一条主线推进← 正确答案
- C.启发式地优先选择产生较短归结式的子句参与配对← 正确答案
- D.拒绝使用任何互补文字对以外的文字
答案:ABC。A 是子句包含删除策略,B 是线性归结策略,C 是启发式选择策略,三者都能显著缩小搜索空间且保持完备性。D 完全错误——归结就是靠互补文字对工作的,拒绝使用它们等于废弃了归结本身。