Lean 语言参考

16.4. 约束传播🔗

约束传播 适用于白板的 TrueFalse 存储桶。 每当将术语添加到其中一个存储桶时,grind 都会触发数十个小型 forward 规则,这些规则从其逻辑结果中获取更多信息:

布尔连接词

布尔连接词的真值表可用于导出进一步的真假事实。 例如:

  • 如果 ATrue,则 A B 变为 True

  • 如果 A BTrue,则 AB 均变为 True

  • 如果A BFalse,则AB中的至少一个变为False

归纳类型

如果将同一 归纳类型 的两个不同构造函数(例如 nonesome)的应用所形成的项置于同一等价类中,则会产生矛盾。 如果由同一构造函数的应用形成的两个项被放置在同一等价类中,则它们的参数也相等。

预测

h : (x, y) = (x', y') 中我们得出 x = x'y = y'

演员阵容

任何术语 cast h a : β 都立即与 a : α 等同(使用 异构相等)。

减少

定义归约被传播,因此 (a, b).1 等同于 a

下面是传播者的代表性切片,展示了它们的整体风格。 每个都遵循相同的骨架。

  1. 它检查子表达式的真值。

  2. 如果可以导出进一步的事实,它可以使用 (pushEq) 使术语相等(在隐喻白板上连接它们),或者使用 (pushEqTrue / pushEqFalse) 指示真值。 这些步骤使用内部辅助引理(例如 Grind.and_eq_of_eq_true_left)生成证明项。

  3. 如果出现矛盾,则使用 (closeGoal) 关闭目标。

向上传播从有关子项的事实导出有关项的事实,而向下传播从有关项的事实导出有关子项的事实。

/-- Propagate equalities *upwards* for conjunctions. -/ builtin_grind_propagator propagateAndUp And := fun e => do let_expr And a b := e | return () if ( isEqTrue a) then -- a = True ⇒ (a ∧ b) = b pushEq e b <| mkApp3 (mkConst ``Grind.and_eq_of_eq_true_left) a b ( mkEqTrueProof a) else if ( isEqTrue b) then -- b = True ⇒ (a ∧ b) = a pushEq e a <| mkApp3 (mkConst ``Grind.and_eq_of_eq_true_right) a b ( mkEqTrueProof b) else if ( isEqFalse a) then -- a = False ⇒ (a ∧ b) = False pushEqFalse e <| mkApp3 (mkConst ``Grind.and_eq_of_eq_false_left) a b ( mkEqFalseProof a) else if ( isEqFalse b) then -- b = False ⇒ (a ∧ b) = False pushEqFalse e <| mkApp3 (mkConst ``Grind.and_eq_of_eq_false_right) a b ( mkEqFalseProof b) /-- Truth flows *down* when the whole `And` is proven `True`. -/ builtin_grind_propagator propagateAndDown And := fun e => do if ( isEqTrue e) then let_expr And a b := e | return () let h mkEqTrueProof e -- (a ∧ b) = True ⇒ a = True pushEqTrue a <| mkApp3 (mkConst ``Grind.eq_true_of_and_eq_true_left) a b h -- (a ∧ b) = True ⇒ B = True pushEqTrue b <| mkApp3 (mkConst ``Grind.eq_true_of_and_eq_true_right) a b h

其他频繁触发的传播器遵循相同的模式:

传播者

手柄

注释

propagateOrUp / propagateOrDown

A B

使用真值表进行析取以导出进一步的真值

propagateNotUp / propagateNotDown

¬ A

确保 ¬ AA 具有相反的真值

propagateEqUp / propagateEqDown

a = b

桥接布尔值,检测构造函数冲突

propagateIte / propagateDIte

ite / dite

一旦条件的真值已知,则将该项与所选分支等同

propagateEtaStruct

标记为 [grind ext] 的结构的值

生成 η 展开式 a = ⟨a.1, …⟩

Bool 的许多专门变体完全反映了这些规则(例如 propagateBoolAndUp)。

16.4.1. 仅传播示例🔗

这些目标“纯粹”通过约束传播来封闭——没有案例分割,没有理论求解器:

-- Boolean connective: a && !a is always false. example (a : Bool) : (a && !a) = false := a:Bool(a && !a) = false All goals completed! 🐙 -- Conditional (ite): -- once the condition is true, ite picks the 'then' branch. example (c : Bool) (t e : Nat) (h : c = true) : (if c then t else e) = t := c:Boolt:Nate:Nath:c = true(if c = true then t else e) = t All goals completed! 🐙 -- Negation propagates truth downwards. example (a : Bool) (h : (!a) = true) : a = false := a:Boolh:(!a) = truea = false All goals completed! 🐙

这些片段会立即运行,因为一旦假设被内化,相关传播器(propagateBoolAndUppropagateItepropagateBoolNotDown)就会立即触发。 将选项 trace.grind.eqc 设置为 true 会导致 grind 每次两个等价类合并时打印一行,这对于查看实际传播非常方便。

传播规则集随着时间的推移而扩展和完善,因此 InfoView 将显示越来越丰富的 TrueFalse 存储桶。 完整的等价类仅在 grind 失败时自动显示,并且仅针对无法关闭的第一个子目标 - 使用此输出来检查缺失的事实并了解子目标保持打开状态的原因。

Identifying Missing Facts

在此示例中,grind 失败:

example : x = y y = z w = x w = v w = z := α✝:Sort u_1x:α✝y:α✝z:α✝w:α✝v:α✝x = y y = z w = x w = v w = z `grind` failed α:Sort u_1x y z w v:αleft:x = yright:y = zh_1:w = x w = vh_2:¬w = zFalse
[grind] Goal diagnostics
  • [facts] Asserted facts
    • [prop] x = y
    • [prop] y = z
    • [prop] w = x w = v
    • [prop] ¬w = z
  • [eqc] True propositions
    • [prop] w = x w = v
    • [prop] w = v
  • [eqc] False propositions
    • [prop] w = x
    • [prop] w = z
  • [eqc] Equivalence classes
    • [eqc] {x, y, z}
    • [eqc] {w, v}
All goals completed! 🐙

生成的错误消息包括已识别的等价类以及真命题和假命题:

`grind` failed
α:Sort u_1x y z w v:αleft:x = yright:y = zh_1:w = x  w = vh_2:¬w = zFalse
[grind] Goal diagnostics
  • [facts] Asserted facts
    • [prop] x = y
    • [prop] y = z
    • [prop] w = x w = v
    • [prop] ¬w = z
  • [eqc] True propositions
    • [prop] w = x w = v
    • [prop] w = v
  • [eqc] False propositions
    • [prop] w = x
    • [prop] w = z
  • [eqc] Equivalence classes
    • [eqc] {x, y, z}
    • [eqc] {w, v}

x = yy = z 都是通过来自 x = y ∧ y = z 前提的约束传播发现的。 在此证明中,grindw = x ∨ w = v 执行案例拆分。 在第二个分支中,它无法将 wz 置于同一等价类中。