import SFLean4.LF.Basics
import SFLean4.LF.Induction
import SFLean4.LF.Lists
import SFLean4.LF.Poly
import SFLean4.LF.Tactics
import SFLean4.LF.Logic《软件基础》(Software Foundations) 卷一:逻辑基础 (LF)
第七章:归纳命题与关系 (IndProp: Inductively Defined Propositions)
在前几章中,我们学习了构造命题的多种核心方式:
- 等式命题(
e1 = e2); - 全称与蕴含命题(
∀ x, P x与P → Q); - 命题逻辑联结词(
∧,∨,¬,False,True,↔,∃)。
然而,现实计算机科学中存在大量错综复杂、具有无限展开潜力的断言与关系—— 例如:
- 形式语言与操作语义中的转移系统与多步归约(Small-Step / Big-Step Semantics);
- 正则表达式匹配器中字符串与模式的生成判定;
- 列表中元素的排列 (Permutation)、无重复性 (NoDup) 与子序列 (Subsequence) 关系;
- 图论与有限状态机中的传递闭包与可达性。
面对这类问题,仅凭普通函数或简单逻辑联结词往往难以表达(可能受限于停机检查或算法复杂性)。 为此,本章将引入依赖类型论中最强大、最核心的建模工具:归纳定义的命题(Inductively Defined Propositions / Inductive Predicates)!
本章核心学习目标:
- 归纳命题的定义机制:
- 掌握通过推理规则(Inference Rules)声明归纳谓词,理解参数(Parameters)与索引(Indices)的根本区别;
- 学习柯拉茨猜想(Collatz Conjecture)、偶数谓词
ev与排列关系Perm3的直观定义。
- 在证明中解构与使用归纳证据:
- 反演 (Inversion /
cases):学会根据给定的归纳证据,反向枚举并穷尽所有可能生成它的前置条件; - 在证据上进行归纳 (Induction on Evidence):深入理解何时不能对普通数据归纳,而必须直接对命题证据本身进行结构归纳;
- 反演 (Inversion /
- 案例研究:正则表达式的形式化验证:
- 将语法结构
reg_exp与匹配谓词exp_match(记作s =~ re)形式化; - 证明形式语言领域的重磅定理:泵引理 (Pumping Lemma);
- 将语法结构
- 布尔反射与元逻辑深化:
- 探究
reflect归纳结构,建立布尔测试与形式化证据间的无缝跳转; - 证明鸽巢原理(Pigeonhole Principle)与非停滞列表判定;
- 探究
- 扩展案例:经过验证的正则表达式导数匹配器:
- 形式化验证布尔佐夫斯基导数(Brzozowski Derivatives)与正则表达式匹配算法的正确性。
namespace IndProp
open Poly
open Poly.list
open Poly.prod
open Poly.option
open Tactics
open Logic
/-- 皮亚诺后继记号别名,对齐原版 Coq 的 `S` -/
abbrev S := Nat.succ
/-- 自然数零记号别名,对齐原版 Coq 的 `O` -/
abbrev O := 0
/-- 自然数前驱函数别名,对齐原版 Coq 的 `pred` -/
abbrev pred := Nat.pred1. 归纳定义的命题 (Inductively Defined Propositions)
1.1 柯拉茨猜想 (The Collatz Conjecture)
著名的柯拉茨猜想(3n + 1 猜想)指出:任取一个正整数
我们首先定义单步计算函数 csf(Collatz Step Function):
/-- 自然数除以 2 的递归实现 -/
def div2 : Nat → Nat
| 0 => 0
| 1 => 0
| n + 2 => div2 n + 1
/-- 柯拉茨单步步进函数 -/
def csf (n : Nat) : Nat :=
if even n then div2 n
else (3 * n) + 1如果我们试图编写一个递归函数 reaches1_in n 来计算步数,或定义递归谓词 Collatz_holds_for n : Prop, 编译器会断然拒绝——因为
然而,借由归纳命题,我们可以将“最终抵达 1”表述为由三条推理规则生成的证据系统:
- 规则一(基步):1 必定抵达 1;
- 规则二(偶数步):若
为偶数且 div2 n抵达 1,则抵达 1; - 规则三(奇数步):若
为奇数且 3n + 1抵达 1,则抵达 1。
/-- 柯拉茨性质的归纳谓词定义 -/
inductive Collatz_holds_for : Nat → Prop where
| Chf_one : Collatz_holds_for 1
| Chf_even (n : Nat) : even n = true → Collatz_holds_for (div2 n) → Collatz_holds_for n
| Chf_odd (n : Nat) : even n = false → Collatz_holds_for ((3 * n) + 1) → Collatz_holds_for n
/-- 证明 12 满足柯拉茨猜想:构造自下而上的有限推导树证据 -/
theorem Collatz_holds_for_12 : Collatz_holds_for 12 := by
apply Collatz_holds_for.Chf_even (n := 12) <;> try rfl
apply Collatz_holds_for.Chf_even (n := 6) <;> try rfl
apply Collatz_holds_for.Chf_odd (n := 3) <;> try rfl
apply Collatz_holds_for.Chf_even (n := 10) <;> try rfl
apply Collatz_holds_for.Chf_odd (n := 5) <;> try rfl
apply Collatz_holds_for.Chf_even (n := 16) <;> try rfl
apply Collatz_holds_for.Chf_even (n := 8) <;> try rfl
apply Collatz_holds_for.Chf_even (n := 4) <;> try rfl
apply Collatz_holds_for.Chf_even (n := 2) <;> try rfl
exact Collatz_holds_for.Chf_one
/-- 柯拉茨猜想公理陈述:所有非零自然数均满足 Collatz_holds_for -/
axiom collatz : ∀ n : Nat, n ≠ 0 → Collatz_holds_for n1.2 自然数大小比较的二元关系 (Binary Relation for Comparing Numbers)
namespace LePlayground
/-- 自然数小于等于关系的归纳定义 -/
inductive le : Nat → Nat → Prop where
| le_n (n : Nat) : le n n
| le_S (n m : Nat) : le n m → le n (m + 1)
/-- 3 <= 5 的构造性证据示例 -/
theorem le_3_5 : le 3 5 :=
le.le_S 3 4 (le.le_S 3 3 (le.le_n 3))
end LePlayground1.3 传递闭包 (Transitive Closure)
给定任意二元关系 clos_trans R 是包含
/-- 二元关系的传递闭包 -/
inductive clos_trans {X : Type} (R : X → X → Prop) : X → X → Prop where
| t_step (x y : X) : R x y → clos_trans R x y
| t_trans (x y z : X) : clos_trans R x y → clos_trans R y z → clos_trans R x z
/-- 人物类型 -/
inductive Person : Type where
| Sage : Person
| Cleo : Person
| Ridley : Person
| Moss : Person
/-- 父母关系 -/
inductive parent_of : Person → Person → Prop where
| po_SC : parent_of Person.Sage Person.Cleo
| po_SR : parent_of Person.Sage Person.Ridley
| po_CM : parent_of Person.Cleo Person.Moss
/-- 祖先关系:父母关系的传递闭包 -/
def ancestor_of : Person → Person → Prop :=
clos_trans parent_of
/-- 证明 Sage 是 Moss 的祖先 -/
theorem ancestor_of_ex : ancestor_of Person.Sage Person.Moss := by
dsimp [ancestor_of]
apply clos_trans.t_trans Person.Sage Person.Cleo Person.Moss
· exact clos_trans.t_step _ _ parent_of.po_SC
· exact clos_trans.t_step _ _ parent_of.po_CM1.4 自反传递闭包 (Reflexive and Transitive Closure)
/-- 自反传递闭包 -/
inductive clos_refl_trans {X : Type} (R : X → X → Prop) : X → X → Prop where
| rt_step (x y : X) : R x y → clos_refl_trans R x y
| rt_refl (x : X) : clos_refl_trans R x x
| rt_trans (x y z : X) : clos_refl_trans R x y → clos_refl_trans R y z → clos_refl_trans R x z
/-- 柯拉茨单步转移关系 -/
def cs (n m : Nat) : Prop := csf n = m
/-- 柯拉茨多步转移关系:单步转移关系的自反传递闭包 -/
def cms (n m : Nat) : Prop := clos_refl_trans cs n m
/-- 柯拉茨猜想的等价闭包表述 -/
axiom collatz' : ∀ n : Nat, n ≠ 0 → cms n 1🎯 练习:clos_refl_trans_sym 1 星 · standard, optional
/-- 自反、对称且传递闭包 -/
inductive clos_refl_trans_sym {X : Type} (R : X → X → Prop) : X → X → Prop where
| rts_step (x y : X) : R x y → clos_refl_trans_sym R x y
| rts_refl (x : X) : clos_refl_trans_sym R x x
| rts_trans (x y z : X) : clos_refl_trans_sym R x y → clos_refl_trans_sym R y z → clos_refl_trans_sym R x z
| rts_sym (x y : X) : clos_refl_trans_sym R x y → clos_refl_trans_sym R y x1.5 排列关系 (Permutations)
三元素列表置换关系的归纳定义:
/-- 三元素列表的置换关系谓词 -/
inductive Perm3 {X : Type} : list X → list X → Prop where
| perm3_swap12 (a b c : X) : Perm3 [a; b; c] [b; a; c]
| perm3_swap23 (a b c : X) : Perm3 [a; b; c] [a; c; b]
| perm3_trans (l1 l2 l3 : list X) : Perm3 l1 l2 → Perm3 l2 l3 → Perm3 l1 l3🎯 练习:perm 1 星 · standard, optional
根据上述定义,[1; 2; 3] 是否为其自身的置换? 答:是的。因为可通过两次对合交换得到: Perm3 [1; 2; 3] [2; 1; 3] 与 Perm3 [2; 1; 3] [1; 2; 3], 结合 perm3_trans 即可推导 Perm3 [1; 2; 3] [1; 2; 3]。
1.6 偶数命题(第三次相遇) (Evenness yet again)
在前面章节中,我们已经见过了偶数的两种形式化:
- 布尔计算:
even n = true; - 存在量词命题:
Even n ≜ ∃ k, n = double k。
现在,我们给出偶数的归纳谓词定义:
- 0 是偶数(
ev_0); - 若
是偶数,则 也是偶数( ev_SS)。
/-- 偶数的归纳谓词定义 -/
inductive ev : Nat → Prop where
| ev_0 : ev 0
| ev_SS (n : Nat) (h : ev n) : ev (n + 2)
namespace EvPlayground
inductive ev : Nat → Prop where
| ev_0 : ev 0
| ev_SS : ∀ n : Nat, ev n → ev (n + 2)
end EvPlayground
/-- 证明 4 是偶数 -/
theorem ev_4 : ev 4 := by
apply ev.ev_SS
apply ev.ev_SS
exact ev.ev_0
/-- 通过显式函数项组合证据证明 4 是偶数 -/
theorem ev_4' : ev 4 :=
ev.ev_SS 2 (ev.ev_SS 0 ev.ev_0)
/-- 若 n 是偶数,则 n + 4 亦为偶数 -/
theorem ev_plus4 (n : Nat) (hn : ev n) : ev (4 + n) := by
rw [Nat.add_comm]
apply ev.ev_SS
apply ev.ev_SS
exact hn🎯 练习:ev_double 1 星 · standard
/-- 任意自然数翻倍后均为归纳偶数 -/
theorem ev_double (n : Nat) : ev (double n) := by
sorry1.7 构造排列证据 (Constructing Evidence for Permutations)
/-- 证明 [1; 2; 3] 与其逆序 [3; 2; 1] 互为置换 -/
theorem Perm3_rev : Perm3 [1; 2; 3] [3; 2; 1] := by
apply Perm3.perm3_trans (l2 := [2; 3; 1])
· apply Perm3.perm3_trans (l2 := [2; 1; 3])
· exact Perm3.perm3_swap12 1 2 3
· exact Perm3.perm3_swap23 2 1 3
· exact Perm3.perm3_swap12 2 3 1
/-- 函数项构造证明 Perm3_rev' -/
theorem Perm3_rev' : Perm3 [1; 2; 3] [3; 2; 1] :=
Perm3.perm3_trans [1; 2; 3] [2; 3; 1] [3; 2; 1]
(Perm3.perm3_trans [1; 2; 3] [2; 1; 3] [2; 3; 1]
(Perm3.perm3_swap12 1 2 3)
(Perm3.perm3_swap23 2 1 3))
(Perm3.perm3_swap12 2 3 1)🎯 练习:Perm3 1 星 · standard
/-- 置换示例一 -/
theorem Perm3_ex1 : Perm3 [1; 2; 3] [2; 3; 1] := by
sorry
/-- 置换关系的自反性 -/
theorem Perm3_refl (X : Type) (a b c : X) : Perm3 [a; b; c] [a; b; c] := by
sorry2. 在证明中使用证据 (Using Evidence in Proofs)
2.1 解构与反演证据 (Destructing and Inverting Evidence)
归纳定义不仅为我们提供了构造证据的手段,更宣告了这些构造子是生成证据的仅有方式! 因此,当假设中包含 ev n 时,我们可以反向推导其来源: 要么 n = 0,要么存在 n' 使得 n = n' + 2 且 ev n'。
/-- 偶数反演引理 -/
theorem ev_inversion (n : Nat) (h : ev n) :
n = 0 ∨ ∃ n', n = n' + 2 ∧ ev n' := by
cases h with
| ev_0 => left; rfl
| ev_SS n' h' => right; exact ⟨n', rfl, h'⟩🎯 练习:le_inversion 1 星 · standard
/-- 小于等于关系的反演引理 -/
theorem le_inversion (n m : Nat) (h : LePlayground.le n m) :
n = m ∨ ∃ m', m = m' + 1 ∧ LePlayground.le n m' := by
sorry
/-- 利用反演引理推导两步递减 -/
theorem evSS_ev (n : Nat) (h : ev (n + 2)) : ev n := by
have h_inv := ev_inversion (n + 2) h
rcases h_inv with h0 | ⟨n', hnm, hev⟩
· contradiction
· injection hnm with heq
injection heq with heq'
subst heq'
exact hev
/-- 在 Lean 4 中,直接使用 cases 即可完成现代反演(免除繁琐的手动展开) -/
theorem evSS_ev' (n : Nat) (h : ev (n + 2)) : ev n := by
cases h with
| ev_SS _ h' => exact h'
/-- 1 绝非偶数(手动反演版) -/
theorem one_not_even : ¬(ev 1) := by
intro h
have h_inv := ev_inversion 1 h
rcases h_inv with h0 | ⟨n', hnm, _⟩
· contradiction
· contradiction
/-- 1 绝非偶数(现代 cases 一行秒杀版) -/
theorem one_not_even' : ¬(ev 1) := by
intro h
cases h🎯 练习:inversion_practice 1 星 · standard
/-- 连续四次后继偶数必定蕴含原数为偶数 -/
theorem SSSSev__even (n : Nat) (h : ev (n + 4)) : ev n := by
sorry🎯 练习:ev5_nonsense 1 星 · standard
/-- 从荒谬前提推导出任意结论 -/
theorem ev5_nonsense (h : ev 5) : 2 + 2 = 9 := by
sorry
/-- 反演在等式假设上的应用示例 1 -/
theorem inversion_ex1 (n m o : Nat) (h : [n; m] = [o; o]) : (n :: nil) = (m :: nil) := by
injection h with h1 h2
injection h2 with h3
rw [h1, h3]
/-- 反演在后继不相交等式上的应用示例 2 -/
theorem inversion_ex2 (n : Nat) (contra : n + 1 = 0) : 2 + 2 = 5 := by
contradiction
/-- 尝试对证据执行普通分类讨论(展示归纳步缺乏归纳假设而卡住,原版 Coq 中以 Abort 演示) -/
theorem ev_Even_firsttry (n : Nat) (h : ev n) : Even n := by
-- cases h 只能得到局部子证据,无法推演全称递归性质
sorry2.2 证据上的归纳 (Induction on Evidence)
当我们面对形如 ev n 的前提,并且需要证明关于 h : ev n 进行结构归纳!
/-- 归纳偶数蕴含存在量词翻倍偶数 -/
theorem ev_Even (n : Nat) (h : ev n) : Even n := by
induction h with
| ev_0 => exists 0
| ev_SS n' h' ih =>
rcases ih with ⟨k, hk⟩
exists k + 1
dsimp [double]
rw [hk]
/-- 归纳偶数与存在量词偶数的充要等价性 -/
theorem ev_Even_iff (n : Nat) : ev n ↔ Even n := by
constructor
· exact ev_Even n
· intro ⟨k, hk⟩
rw [hk]
exact ev_double k🎯 练习:ev_sum 2 星 · standard
/-- 两个偶数之和仍为偶数 -/
theorem ev_sum (n m : Nat) (hn : ev n) (hm : ev m) : ev (n + m) := by
sorry🎯 练习:ev_ev__ev 3 星 · advanced, especially useful
/-- 偶数减去偶数仍为偶数 -/
theorem ev_ev__ev (n m : Nat) (hnm : ev (n + m)) (hn : ev n) : ev m := by
sorry🎯 练习:ev_plus_plus 3 星 · standard, optional
/-- 偶数传递加法性质 -/
theorem ev_plus_plus (n m p : Nat) (h1 : ev (n + m)) (h2 : ev (n + p)) : ev (m + p) := by
sorry🎯 练习:ev'_ev 4 星 · advanced, optional
/-- 偶数的另一种双项归纳定义 -/
inductive ev' : Nat → Prop where
| ev'_0 : ev' 0
| ev'_2 : ev' 2
| ev'_sum (n m : Nat) (hn : ev' n) (hm : ev' m) : ev' (n + m)
theorem ev'_ev (n : Nat) : ev' n ↔ ev n := by
sorry
namespace Perm3Reminder
inductive Perm3 {X : Type} : list X → list X → Prop where
| perm3_swap12 (a b c : X) : Perm3 [a; b; c] [b; a; c]
| perm3_swap23 (a b c : X) : Perm3 [a; b; c] [a; c; b]
| perm3_trans (l1 l2 l3 : list X) : Perm3 l1 l2 → Perm3 l2 l3 → Perm3 l1 l3
end Perm3Reminder
/-- 置换关系的对称性(对置换证据进行归纳) -/
theorem Perm3_symm (X : Type) (l1 l2 : list X) (h : Perm3 l1 l2) : Perm3 l2 l1 := by
induction h with
| perm3_swap12 a b c => exact Perm3.perm3_swap12 b a c
| perm3_swap23 a b c => exact Perm3.perm3_swap23 a c b
| perm3_trans _ _ _ _ _ ih1 ih2 => exact Perm3.perm3_trans _ _ _ ih2 ih1🎯 练习:Perm3_In 2 星 · standard
/-- 置换保持列表元素隶属度 -/
theorem Perm3_In (X : Type) (x : X) (l1 l2 : list X) (h : Perm3 l1 l2) (hin : In x l1) : In x l2 := by
sorry🎯 练习:Perm3_NotIn 1 星 · standard, optional
/-- 置换保持元素不隶属性质 -/
theorem Perm3_NotIn (X : Type) (x : X) (l1 l2 : list X) (h : Perm3 l1 l2) (hnin : ¬In x l1) : ¬In x l2 := by
sorry🎯 练习:NotPerm3 2 星 · standard, optional
/-- 长度不一致的列表绝非置换 -/
theorem Perm3_example2 : ¬Perm3 [1; 2; 3] [1; 2] := by
sorry3. 归纳关系的综合练习 (Exercising with Inductive Relations)
namespace Playground
/-- 标准小于等于关系的归纳定义 -/
inductive le (n : Nat) : Nat → Prop where
| le_n : le n n
| le_S (m : Nat) (h : le n m) : le n (m + 1)
scoped notation:50 (priority := high) n:51 " <= " m:51 => le n m
theorem test_le1 : 3 <= 3 := le.le_n
theorem test_le2 : 3 <= 6 := le.le_S 5 (le.le_S 4 (le.le_S 3 le.le_n))
theorem test_le3 : (2 <= 1) → 2 + 2 = 5 := by
intro h
cases h with
| le_S _ h' => cases h'
def lt (n m : Nat) : Prop := le (n + 1) m
def ge (n m : Nat) : Prop := le m n
scoped notation:50 (priority := high) n:51 " < " m:51 => lt n m
scoped notation:50 (priority := high) n:51 " >= " m:51 => ge n m🎯 练习:le_facts 3 星 · standard, especially useful
theorem le_trans (m n o : Nat) (h1 : m <= n) (h2 : n <= o) : m <= o := by
sorry
theorem O_le_n (n : Nat) : 0 <= n := by
sorry
theorem n_le_m__Sn_le_Sm (n m : Nat) (h : n <= m) : (n + 1) <= (m + 1) := by
sorry
theorem Sn_le_Sm__n_le_m (n m : Nat) (h : (n + 1) <= (m + 1)) : n <= m := by
sorry
theorem le_plus_l (a b : Nat) : a <= a + b := by
sorry🎯 练习:plus_le_facts1 2 星 · standard, especially useful
theorem plus_le (n1 n2 m : Nat) (h : n1 + n2 <= m) : n1 <= m ∧ n2 <= m := by
sorry
theorem plus_le_cases (n m p q : Nat) (h : n + m <= p + q) : n <= p ∨ m <= q := by
sorry🎯 练习:plus_le_facts2 2 星 · standard, especially useful
theorem plus_le_compat_l (n m p : Nat) (h : n <= m) : p + n <= p + m := by
sorry
theorem plus_le_compat_r (n m p : Nat) (h : n <= m) : n + p <= m + p := by
sorry
theorem le_plus_trans (n m p : Nat) (h : n <= m) : n <= m + p := by
sorry🎯 练习:lt_facts 3 星 · standard, optional
theorem lt_ge_cases (n m : Nat) : n < m ∨ n >= m := by
sorry
theorem n_lt_m__n_le_m (n m : Nat) (h : n < m) : n <= m := by
sorry
theorem plus_lt (n1 n2 m : Nat) (h : n1 + n2 < m) : n1 < m ∧ n2 < m := by
sorry🎯 练习:leb_le 4 星 · standard, optional
theorem leb_complete (n m : Nat) (h : (n <=? m) = true) : n <= m := by
sorry
theorem leb_correct (n m : Nat) (h : n <= m) : (n <=? m) = true := by
sorry
theorem leb_iff (n m : Nat) : (n <=? m) = true ↔ n <= m := by
sorry
theorem leb_true_trans (n m o : Nat) (h1 : (n <=? m) = true) (h2 : (m <=? o) = true) :
(n <=? o) = true := by
sorry
end Playground
open Playground
namespace R
/-- #### 练习:3 星, standard, especially useful (R_provability) -/
inductive R : Nat → Nat → Nat → Prop where
| c1 : R 0 0 0
| c2 (m n o : Nat) (h : R m n o) : R (m + 1) n (o + 1)
| c3 (m n o : Nat) (h : R m n o) : R m (n + 1) (o + 1)
| c4 (m n o : Nat) (h : R (m + 1) (n + 1) (o + 2)) : R m n o
| c5 (m n o : Nat) (h : R m n o) : R n m o讨论命题 R 1 1 2 与 R 2 2 6 的可证性:
R 1 1 2是可证的(c1 → c2 → c3);R 2 2 6是不可证的(因为关系 R 本质上刻画了加法 m + n = o,而 2 + 2 ≠ 6)。
def manual_grade_for_R_provability : Option (Nat × String) := none
/-- #### 练习:3 星, standard, optional (R_fact) -/
def fR (m n : Nat) : Nat := m + n
theorem R_equiv_fR (m n o : Nat) : R m n o ↔ fR m n = o := by
sorry
end R🎯 练习:subsequence 4 星 · advanced
/-- 列表子序列关系的归纳定义 -/
inductive subseq : list Nat → list Nat → Prop where
| subseq0 (l : list Nat) : subseq nil l
| subseq1 (x : Nat) (l1 l2 : list Nat) (h : subseq l1 l2) : subseq (x :: l1) (x :: l2)
| subseq2 (x : Nat) (l1 l2 : list Nat) (h : subseq l1 l2) : subseq l1 (x :: l2)
theorem subseq_refl (l : list Nat) : subseq l l := by
sorry
theorem subseq_app (l1 l2 l3 : list Nat) (h : subseq l1 l2) : subseq l1 (l2 ++ l3) := by
sorry
theorem subseq_trans (l1 l2 l3 : list Nat) (h1 : subseq l1 l2) (h2 : subseq l2 l3) : subseq l1 l3 := by
sorry🎯 练习:R_provability2 2 星 · standard, optional
考虑归纳关系:
- c1 : R 0 []
- c2 : R (n+1) (n :: l) 由 R n l
- c3 : R n l 由 R (n+1) l
讨论:
- R 2 [1; 0] 可证;
- R 1 [1; 2; 1; 0] 可证;
- R 6 [3; 2; 1; 0] 不可证。
4. 案例研究:正则表达式 (Case Study: Regular Expressions)
/-- 多态正则表达式数据结构 -/
inductive reg_exp (T : Type) : Type where
| EmptySet : reg_exp T
| EmptyStr : reg_exp T
| Char (t : T) : reg_exp T
| App (r1 r2 : reg_exp T) : reg_exp T
| Union (r1 r2 : reg_exp T) : reg_exp T
| Star (r : reg_exp T) : reg_exp T
open reg_exp
/-- 正则表达式匹配归纳谓词 -/
inductive exp_match {T : Type} : list T → reg_exp T → Prop where
| MEmpty : exp_match nil EmptyStr
| MChar (x : T) : exp_match [x] (Char x)
| MApp (s1 : list T) (re1 : reg_exp T) (s2 : list T) (re2 : reg_exp T)
(h1 : exp_match s1 re1) (h2 : exp_match s2 re2) :
exp_match (s1 ++ s2) (App re1 re2)
| MUnionL (s1 : list T) (re1 re2 : reg_exp T)
(h1 : exp_match s1 re1) :
exp_match s1 (Union re1 re2)
| MUnionR (s2 : list T) (re1 re2 : reg_exp T)
(h2 : exp_match s2 re2) :
exp_match s2 (Union re1 re2)
| MStar0 (re : reg_exp T) : exp_match nil (Star re)
| MStarApp (s1 s2 : list T) (re : reg_exp T)
(h1 : exp_match s1 re) (h2 : exp_match s2 (Star re)) :
exp_match (s1 ++ s2) (Star re)
scoped notation:50 (priority := high) s:51 " =~ " re:51 => exp_match s re
open exp_match
theorem reg_exp_ex1 : [1] =~ Char 1 := by
exact MChar 1
theorem reg_exp_ex2 : [1; 2] =~ App (Char 1) (Char 2) := by
have h := @MApp Nat [1] (Char 1) [2] (Char 2) (MChar 1) (MChar 2)
exact h
theorem reg_exp_ex3 : ¬([1; 2] =~ Char 1) := by
intro h
generalize hs : ([1; 2] : list Nat) = s at h
cases h
injection hs
contradiction
/-- 从列表构造精确匹配该列表的正则表达式 -/
def reg_exp_of_list {T : Type} : list T → reg_exp T
| nil => EmptyStr
| x :: l' => App (Char x) (reg_exp_of_list l')
theorem reg_exp_ex4 : [1; 2; 3] =~ reg_exp_of_list [1; 2; 3] := by
dsimp [reg_exp_of_list]
have h1 := @MApp Nat [1] (Char 1) [2; 3] (App (Char 2) (App (Char 3) EmptyStr))
apply h1
· exact MChar 1
· have h2 := @MApp Nat [2] (Char 2) [3] (App (Char 3) EmptyStr)
apply h2
· exact MChar 2
· have h3 := @MApp Nat [3] (Char 3) nil EmptyStr
apply h3
· exact MChar 3
· exact MEmpty
/-- 单项匹配直接提升至 Star 匹配 -/
theorem MStar1 {T : Type} (s : list T) (re : reg_exp T) (h : s =~ re) : s =~ Star re := by
have h' : s = s ++ nil := by rw [Poly.app_nil_r]
rw [h']
exact MStarApp s nil re h (MStar0 re)🎯 练习:exp_match_ex1 3 星 · standard
theorem EmptySet_is_empty (T : Type) (s : list T) : ¬(s =~ EmptySet) := by
sorry
theorem MUnion' (T : Type) (s : list T) (re1 re2 : reg_exp T)
(h : s =~ re1 ∨ s =~ re2) : s =~ Union re1 re2 := by
sorry
theorem MStar' (T : Type) (ss : list (list T)) (re : reg_exp T)
(h : ∀ s, In s ss → s =~ re) : fold app ss nil =~ Star re := by
sorry🎯 练习:EmptyStr_not_needed 2 星 · standard, optional
def EmptyStr' {T : Type} : reg_exp T := Star EmptySet
theorem EmptyStr_not_needed (T : Type) (s : list T) :
s =~ EmptyStr ↔ s =~ EmptyStr' := by
sorry
/-- 提取正则表达式中出现的所有字符 -/
def re_chars {T : Type} : reg_exp T → list T
| .EmptySet => nil
| .EmptyStr => nil
| .Char x => x :: nil
| .App re1 re2 => re_chars re1 ++ re_chars re2
| .Union re1 re2 => re_chars re1 ++ re_chars re2
| .Star re => re_chars re
theorem in_re_match (T : Type) (s : list T) (re : reg_exp T) (x : T)
(h : s =~ re) (hin : In x s) : In x (re_chars re) := by
sorry🎯 练习:re_not_empty 4 星 · standard
def re_not_empty {T : Type} : reg_exp T → Bool
| .EmptySet => false
| .EmptyStr => true
| .Char _ => true
| .App re1 re2 => re_not_empty re1 && re_not_empty re2
| .Union re1 re2 => re_not_empty re1 || re_not_empty re2
| .Star _ => true
theorem re_not_empty_correct (T : Type) (re : reg_exp T) :
(∃ s : list T, s =~ re) ↔ re_not_empty re = true := by
sorry
/-- Star 构造下的拼接封闭引理(首次受阻尝试) -/
theorem star_app_firsttry {T : Type} (s1 s2 : list T) (re : reg_exp T)
(h1 : s1 =~ Star re) (h2 : s2 =~ Star re) : s1 ++ s2 =~ Star re := by
sorry
theorem star_app {T : Type} (s1 s2 : list T) (re : reg_exp T)
(h1 : s1 =~ Star re) (h2 : s2 =~ Star re) : s1 ++ s2 =~ Star re := by
sorry🎯 练习:exp_match_ex2 4 星 · standard, optional
theorem MStar'' (T : Type) (s : list T) (re : reg_exp T) (h : s =~ Star re) :
∃ ss : list (list T), s = fold app ss nil ∧ ∀ s', In s' ss → s' =~ re := by
sorry
/-- 泵引理常数计算函数 -/
def pumping_constant {T : Type} : reg_exp T → Nat
| .EmptySet => 1
| .EmptyStr => 1
| .Char _ => 2
| .App re1 re2 => pumping_constant re1 + pumping_constant re2
| .Union re1 re2 => pumping_constant re1 + pumping_constant re2
| .Star r => pumping_constant r
theorem pumping_constant_ge_1 (T : Type) (re : reg_exp T) :
pumping_constant re >= 1 := by
sorry
theorem pumping_constant_0_false (T : Type) (re : reg_exp T)
(h : pumping_constant re = 0) : False := by
sorry
/-- 字符串的 n 次自拼接重复 -/
def napp {T : Type} : Nat → list T → list T
| 0, _ => nil
| n' + 1, l => l ++ napp n' l
theorem napp_plus (T : Type) (n m : Nat) (l : list T) :
napp (n + m) l = napp n l ++ napp m l := by
sorry
theorem napp_star (T : Type) (m : Nat) (s1 s2 : list T) (re : reg_exp T)
(hs1 : s1 =~ re) (hs2 : s2 =~ Star re) :
napp m s1 ++ s2 =~ Star re := by
sorry🎯 练习:weak_pumping 5 星 · advanced
theorem weak_pumping {T : Type} (re : reg_exp T) (s : list T)
(hm : s =~ re) (hl : pumping_constant re <= length s) :
∃ s1 s2 s3 : list T,
s = s1 ++ s2 ++ s3 ∧
s2 ≠ nil ∧
∀ m : Nat, s1 ++ napp m s2 ++ s3 =~ re := by
sorry🎯 练习:pumping 5 星 · advanced, optional
theorem pumping {T : Type} (re : reg_exp T) (s : list T)
(hm : s =~ re) (hl : pumping_constant re <= length s) :
∃ s1 s2 s3 : list T,
s = s1 ++ s2 ++ s3 ∧
s2 ≠ nil ∧
Playground.le (length s1 + length s2) (pumping_constant re) ∧
∀ m : Nat, s1 ++ napp m s2 ++ s3 =~ re := by
sorry5. 案例研究:深化布尔反射 (Case Study: Improving Reflection)
theorem filter_not_empty_In (n : Nat) (l : list Nat)
(h : filter (fun x => (n =? x)) l ≠ nil) : In n l := by
sorry
/-- 反射归纳谓词:将命题证据与布尔判定紧密关联 -/
inductive reflect (P : Prop) : Bool → Prop where
| ReflectT (h : P) : reflect P true
| ReflectF (h : ¬P) : reflect P false
theorem iff_reflect (P : Prop) (b : Bool) (h : P ↔ b = true) : reflect P b := by
cases b with
| true =>
apply reflect.ReflectT
exact h.mpr rfl
| false =>
apply reflect.ReflectF
intro hp
have hb := h.mp hp
contradiction🎯 练习:reflect_iff 2 星 · standard, especially useful
theorem reflect_iff (P : Prop) (b : Bool) (h : reflect P b) : P ↔ b = true := by
sorry
theorem eqbP (n m : Nat) : reflect (n = m) (n =? m) := by
apply iff_reflect
exact (eqb_eq n m).symm
theorem filter_not_empty_In' (n : Nat) (l : list Nat)
(h : filter (fun x => (n =? x)) l ≠ nil) : In n l := by
sorry
/-- 计数函数 -/
def count (n : Nat) : list Nat → Nat
| nil => 0
| x :: l' => (if (n =? x) then 1 else 0) + count n l'🎯 练习:eqbP_practice 3 星 · standard, especially useful
theorem eqbP_practice (n : Nat) (l : list Nat) (h : count n l = 0) : ¬(In n l) := by
sorry6. 进阶综合练习 (Additional Exercises)
🎯 练习:nostutter_defn 3 星 · standard, especially useful
/-- 无连续重复项(非停滞)列表谓词 -/
inductive nostutter {X : Type} : list X → Prop where
| nostutter_nil : nostutter nil
| nostutter_one (x : X) : nostutter [x]
| nostutter_cons (x y : X) (l : list X) (h1 : x ≠ y) (h2 : nostutter (y :: l)) :
nostutter (x :: y :: l)
theorem test_nostutter_1 : nostutter [3; 1; 4; 1; 5; 6] := by
sorry
theorem test_nostutter_2 : nostutter (@nil Nat) := by
sorry
theorem test_nostutter_3 : nostutter [5] := by
sorry
theorem test_nostutter_4 : ¬(nostutter [3; 1; 1; 4]) := by
sorry
def manual_grade_for_nostutter : Option (Nat × String) := none🎯 练习:filter_challenge 4 星 · advanced
/-- 两个列表归并交错生成第三个列表的归纳关系 -/
inductive merge {X : Type} : list X → list X → list X → Prop where
| merge_nil : merge nil nil nil
| merge_l (x : X) (l1 l2 l : list X) (h : merge l1 l2 l) : merge (x :: l1) l2 (x :: l)
| merge_r (y : X) (l1 l2 l : list X) (h : merge l1 l2 l) : merge l1 (y :: l2) (y :: l)
theorem merge_filter (X : Type) (test : X → Bool) (l l1 l2 : list X)
(hm : merge l1 l2 l)
(h1 : All (fun n => test n = true) l1)
(h2 : All (fun n => test n = false) l2) :
filter test l = l1 := by
sorry🎯 练习:filter_challenge_2 5 星 · advanced, optional
theorem subs_filter (test : Nat → Bool) (l1 l2 : list Nat)
(hsub : subseq l1 l2)
(hall : All (fun x => test x = true) l1) :
Playground.le (length l1) (length (filter test l2)) := by
sorry🎯 练习:palindromes 4 星 · standard, optional
/-- 回文列表归纳谓词 -/
inductive pal {X : Type} : list X → Prop where
| pal_nil : pal nil
| pal_one (x : X) : pal [x]
| pal_cons (x : X) (l : list X) (h : pal l) : pal (x :: l ++ [x])
theorem pal_app_rev (X : Type) (l : list X) : pal (l ++ rev l) := by
sorry
theorem pal_rev (X : Type) (l : list X) (h : pal l) : l = rev l := by
sorry🎯 练习:palindrome_converse 5 星 · standard, optional
theorem palindrome_converse {X : Type} (l : list X) (h : l = rev l) : pal l := by
sorry🎯 练习:NoDup 4 星 · advanced, optional
/-- 两个列表无交集 -/
inductive disjoint {X : Type} : list X → list X → Prop where
| disjoint0 (l2 : list X) : disjoint nil l2
| disjoint1 (x : X) (l1 l2 : list X) (h1 : ¬In x l2) (h2 : disjoint l1 l2) :
disjoint (x :: l1) l2
/-- 列表中无任何重复元素 -/
inductive NoDup {X : Type} : list X → Prop where
| NoDup0 : NoDup nil
| NoDup1 (x : X) (l : list X) (h1 : ¬In x l) (h2 : NoDup l) :
NoDup (x :: l)
theorem disjoint_NoDup_app (X : Type) (l1 l2 : list X)
(h1 : NoDup l1) (h2 : NoDup l2) (hd : disjoint l1 l2) :
NoDup (l1 ++ l2) := by
sorry
theorem NoDup_app (X : Type) (l1 l2 : list X) (h : NoDup (l1 ++ l2)) :
NoDup l1 ∧ NoDup l2 := by
sorry
theorem NoDup_app_disjoint (X : Type) (l1 l2 : list X) (h : NoDup (l1 ++ l2)) :
disjoint l1 l2 := by
sorry
def manual_grade_for_NoDup_disjoint_etc : Option (Nat × String) := none🎯 练习:pigeonhole_principle 4 星 · advanced, optional
theorem in_split (X : Type) (x : X) (l : list X) (h : In x l) :
∃ l1 l2 : list X, l = l1 ++ x :: l2 := by
sorry
/-- 列表包含重复元素归纳谓词 -/
inductive repeats {X : Type} : list X → Prop where
| repeats_trans (x : X) (l : list X) (h : In x l) : repeats (x :: l)
| repeats_more (x : X) (l : list X) (h : repeats l) : repeats (x :: l)
def manual_grade_for_check_repeats : Option (Nat × String) := none
/-- 鸽巢原理(结合排中律公理) -/
theorem pigeonhole_principle (hem : excluded_middle) (X : Type) (l1 l2 : list X)
(hin : ∀ x, In x l1 → In x l2)
(hlen : Playground.lt (length l2) (length l1)) :
repeats l1 := by
sorry7. 扩展案例:可验证的正则表达式匹配器 (Extended Exercise: A Verified Regular-Expression Matcher)
abbrev ascii := _root_.Char
def string := list ascii
theorem provable_equiv_true (P : Prop) (h : P) : (P ↔ True) := by
constructor
· intro _; trivial
· intro _; exact h
theorem not_equiv_false (P : Prop) (h : ¬P) : (P ↔ False) := by
constructor
· intro hp; exact h hp
· intro contra; cases contra
theorem null_matches_none (s : string) : (s =~ EmptySet) ↔ False := by
constructor
· intro h; cases h
· intro contra; cases contra
theorem empty_matches_eps (s : string) : (s =~ EmptyStr) ↔ s = nil := by
constructor
· intro h
generalize hr : (EmptyStr : reg_exp ascii) = re at h
cases h
all_goals cases hr
rfl
· intro h; rw [h]; exact MEmpty
theorem empty_nomatch_ne (a : ascii) (s : string) : (a :: s =~ EmptyStr) ↔ False := by
constructor
· intro h
generalize hs : a :: s = s' at h
generalize hr : (EmptyStr : reg_exp ascii) = re at h
cases h
all_goals cases hr
cases hs
· intro contra; cases contra
theorem char_nomatch_char (a b : ascii) (s : string) (hne : b ≠ a) :
(b :: s =~ reg_exp.Char a) ↔ False := by
constructor
· intro h
generalize hs : b :: s = s' at h
generalize hr : (reg_exp.Char a : reg_exp ascii) = re at h
cases h
all_goals cases hr
injection hs with hb _
exact hne hb
· intro contra; cases contra
theorem char_eps_suffix (a : ascii) (s : string) : (a :: s =~ reg_exp.Char a) ↔ s = nil := by
constructor
· intro h
generalize hs : a :: s = s' at h
generalize hr : (reg_exp.Char a : reg_exp ascii) = re at h
cases h
all_goals cases hr
injection hs
· intro h
rw [h]
exact MChar a
theorem app_exists (s : string) (re0 re1 : reg_exp ascii) :
(s =~ App re0 re1) ↔ ∃ s0 s1 : string, s = s0 ++ s1 ∧ s0 =~ re0 ∧ s1 =~ re1 := by
constructor
· intro h
generalize hr : (App re0 re1 : reg_exp ascii) = re at h
cases h
all_goals cases hr
exact ⟨_, _, rfl, by assumption, by assumption⟩
· intro ⟨s0, s1, heq, h1, h2⟩
rw [heq]
exact MApp s0 re0 s1 re1 h1 h2🎯 练习:app_ne 3 星 · standard, optional
theorem app_ne (a : ascii) (s : string) (re0 re1 : reg_exp ascii) :
(a :: s =~ App re0 re1) ↔
((nil =~ re0 ∧ a :: s =~ re1) ∨
∃ s0 s1, s = s0 ++ s1 ∧ a :: s0 =~ re0 ∧ s1 =~ re1) := by
sorry
theorem union_disj (s : string) (re0 re1 : reg_exp ascii) :
(s =~ Union re0 re1) ↔ (s =~ re0 ∨ s =~ re1) := by
constructor
· intro h
generalize hr : (Union re0 re1 : reg_exp ascii) = re at h
cases h
all_goals cases hr
· exact Or.inl (by assumption)
· exact Or.inr (by assumption)
· intro
| Or.inl h1 => exact MUnionL s re0 re1 h1
| Or.inr h2 => exact MUnionR s re0 re1 h2🎯 练习:star_ne 3 星 · standard, optional
theorem star_ne (a : ascii) (s : string) (re : reg_exp ascii) :
(a :: s =~ Star re) ↔
∃ s0 s1, s = s0 ++ s1 ∧ a :: s0 =~ re ∧ s1 =~ Star re := by
sorry
def refl_matches_eps (m : reg_exp ascii → Bool) : Prop :=
∀ re : reg_exp ascii, reflect (nil =~ re) (m re)🎯 练习:match_eps 2 星 · standard, optional
def match_eps : reg_exp ascii → Bool
| .EmptySet => false
| .EmptyStr => true
| .Char _ => false
| .App re1 re2 => match_eps re1 && match_eps re2
| .Union re1 re2 => match_eps re1 || match_eps re2
| .Star _ => true🎯 练习:match_eps_refl 3 星 · standard, optional
theorem match_eps_refl : refl_matches_eps match_eps := by
sorry
def is_der (re : reg_exp ascii) (a : ascii) (re' : reg_exp ascii) : Prop :=
∀ s : string, (a :: s =~ re) ↔ s =~ re'
def derives (d : ascii → reg_exp ascii → reg_exp ascii) : Prop :=
∀ a re, is_der re a (d a re)🎯 练习:derive 3 星 · standard, optional
def derive (a : ascii) : reg_exp ascii → reg_exp ascii
| .EmptySet => .EmptySet
| .EmptyStr => .EmptySet
| .Char x => if x == a then .EmptyStr else .EmptySet
| .App re1 re2 =>
if match_eps re1 then .Union (derive a re2) (.App (derive a re1) re2)
else .App (derive a re1) re2
| .Union re1 re2 => .Union (derive a re1) (derive a re2)
| .Star re => .App (derive a re) (.Star re)
def c : ascii := 'c'
def d : ascii := 'd'
theorem test_der0 : match_eps (derive c .EmptySet) = false := by rfl
theorem test_der1 : match_eps (derive c (.Char c)) = true := by rfl
theorem test_der2 : match_eps (derive c (.Char d)) = false := by rfl
theorem test_der3 : match_eps (derive c (.App (.Char c) .EmptyStr)) = true := by rfl
theorem test_der4 : match_eps (derive c (.App .EmptyStr (.Char c))) = true := by rfl
theorem test_der5 : match_eps (derive c (.Star (.Char c))) = true := by rfl
theorem test_der6 : match_eps (derive d (derive c (.App (.Char c) (.Char d)))) = true := by rfl
theorem test_der7 : match_eps (derive d (derive c (.App (.Char d) (.Char c)))) = false := by rfl🎯 练习:derive_corr 4 星 · standard, optional
theorem derive_corr : derives derive := by
sorry
def matches_regex (m : string → reg_exp ascii → Bool) : Prop :=
∀ (s : string) (re : reg_exp ascii), reflect (s =~ re) (m s re)🎯 练习:regex_match 2 星 · standard, optional
def regex_match : string → reg_exp ascii → Bool
| nil, re => match_eps re
| a :: s', re => regex_match s' (derive a re)🎯 练习:regex_match_correct 3 星 · standard, optional
theorem regex_match_correct : matches_regex regex_match := by
sorry
end IndProp