-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathConfluence.lean
188 lines (156 loc) · 6.93 KB
/
Confluence.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
-- https://plfa.github.io/Confluence/
import Plfl.Init
import Plfl.Untyped
import Plfl.Untyped.Substitution
namespace Confluence
open Untyped.Notation
-- https://plfa.github.io/Confluence/#parallel-reduction
/--
Parallel reduction.
-/
inductive PReduce : (Γ ⊢ a) → (Γ ⊢ a) → Prop where
| var : PReduce (` x) (` x)
| lamβ : PReduce n n' → PReduce v v' → PReduce ((ƛ n) □ v) (n'⟦v'⟧)
| lamζ : PReduce n n' → PReduce (ƛ n) (ƛ n')
| apξ : PReduce l l' → PReduce m m' → PReduce (l □ m) (l' □ m')
namespace PReduce
@[refl]
theorem refl (m : Γ ⊢ a) : PReduce m m := by
match m with
| ` i => exact .var
| ƛ n => apply lamζ; apply refl
| l □ m => apply apξ <;> apply refl
abbrev Clos {Γ a} := Relation.ReflTransGen (α := Γ ⊢ a) PReduce
end PReduce
open Relation.ReflTransGen (head_induction_on)
namespace Notation
scoped infix:20 " ⇛ " => PReduce
scoped infix:20 " ⇛* " => PReduce.Clos
end Notation
open Notation
namespace PReduce.Clos
abbrev single (p : m ⇛ n) : (m ⇛* n) := .head p .refl
abbrev tail : (m ⇛* n) → (n ⇛ n') → (m ⇛* n') := .tail
abbrev trans : (m ⇛* n) → (n ⇛* n') → (m ⇛* n') := .trans
instance : Coe (m ⇛ n) (m ⇛* n) where coe := .single
end PReduce.Clos
namespace PReduce
instance : IsRefl (Γ ⊢ a) PReduce where refl := .refl
instance : Trans (α := Γ ⊢ a) Clos Clos Clos where trans := .trans
instance : Trans (α := Γ ⊢ a) Clos PReduce Clos where trans c r := c.tail r
instance : Trans (α := Γ ⊢ a) PReduce PReduce Clos where trans r r' := .tail r r'
instance : Trans (α := Γ ⊢ a) PReduce Clos Clos where trans r c := .head r c
-- https://plfa.github.io/Confluence/#equivalence-between-parallel-reduction-and-reduction
def fromReduce {Γ a} {m n : Γ ⊢ a} : m —→ n → (m ⇛ n) := by intro
| .lamβ => refine .lamβ ?rn ?rv <;> rfl
| .lamζ rn => refine .lamζ ?_; exact fromReduce rn
| .apξ₁ rl => refine .apξ ?_ (by rfl); exact fromReduce rl
| .apξ₂ rm => refine .apξ (by rfl) ?_; exact fromReduce rm
def toReduceClos : (m ⇛ n) → (m —↠ n) := open Untyped.Reduce in by intro
| .var => rfl
| .lamβ rn rv => rename_i n n' v v'; calc (ƛ n) □ v
_ —↠ (ƛ n') □ v := by refine ap_congr₁ (toReduceClos ?_); exact .lamζ rn
_ —↠ (ƛ n') □ v' := ap_congr₂ rv.toReduceClos
_ —→ n'⟦v'⟧ := .lamβ
| .lamζ rn => apply lam_congr; exact rn.toReduceClos
| .apξ rl rm => rename_i l l' m m'; calc l □ m
_ —↠ l' □ m := ap_congr₁ rl.toReduceClos
_ —↠ l' □ m' := ap_congr₂ rm.toReduceClos
end PReduce
instance instNonemptyPReduceReduceClos : (m ⇛* n) ≃ (m —↠ n) where
toFun := toFun
invFun := invFun
left_inv _ := by simp only
right_inv _ := by simp only
where
toFun {m n} : (m ⇛* n) → (m —↠ n) := by
intro rs; induction rs using head_induction_on with
| refl => rfl
| head r _ => apply r.toReduceClos.trans; trivial
invFun {m n} : (m —↠ n) → (m ⇛* n) := by
intro rs; induction rs using head_induction_on with
| refl => rfl
| head r _ => refine .head (PReduce.fromReduce r) ?_; trivial
open Untyped.Subst
open Substitution
-- https://plfa.github.io/Confluence/#substitution-lemma-for-parallel-reduction
abbrev par_subst (σ : Subst Γ Δ) (σ' : Subst Γ Δ) := ∀ {a} {x : Γ ∋ a}, σ x ⇛ σ' x
section
lemma par_rename {ρ : Rename Γ Δ} {m m' : Γ ⊢ a} : (m ⇛ m') → (rename ρ m ⇛ rename ρ m')
:= open PReduce in by intro
| .var => exact .var
| .lamζ rn => apply lamζ; apply par_rename; trivial
| .apξ rl rm => apply apξ <;> (apply par_rename; trivial)
| .lamβ rn rv =>
rename_i n n' v v'; have rn' := par_rename (ρ := ext ρ) rn; have rv' := par_rename (ρ := ρ) rv
have := lamβ rn' rv'; rwa [rename_subst_comm] at this
theorem par_subst_exts {σ τ : Subst Γ Δ} (s : par_subst σ τ)
: ∀ {b}, par_subst (exts (b := b) σ) (exts τ)
:= by
intro _ _; intro
| .z => exact .var
| .s i => exact par_rename s
theorem subst_par {σ τ : Subst Γ Δ} {m m' : Γ ⊢ a}
(s : par_subst σ τ) (p : m ⇛ m') : (⟪σ⟫ m ⇛ ⟪τ⟫ m')
:= open PReduce in by
match p with
| .var => exact s
| .lamβ pn pv => rw [←subst_comm]; apply_rules [lamβ, subst_par, par_subst_exts]
| .lamζ pn => apply_rules [lamζ, subst_par, par_subst_exts]
| .apξ pl pm => apply_rules [apξ, subst_par]
variable {n n' : Γ‚ a ⊢ b} {m m': Γ ⊢ a}
theorem par_subst₁σ (p : m ⇛ m') : par_subst (subst₁σ m) (subst₁σ m') := by
intro _ i; cases i with simp only [subst₁σ]
| z => exact p
| s i => exact .var
theorem sub_par (pn : n ⇛ n') (pm : m ⇛ m') : n⟦m⟧ ⇛ n'⟦m'⟧ :=
subst_par (par_subst₁σ pm) pn
end
-- https://plfa.github.io/Confluence/#parallel-reduction-satisfies-the-diamond-property
/--
Many parallel reductions at once.
-/
abbrev PReduce.plus : (Γ ⊢ a) → (Γ ⊢ a)
| ` i => ` i
| ƛ n => ƛ (plus n)
| (ƛ n) □ m => plus n⟦plus m⟧
| l □ m => plus l □ plus m
namespace Notation
postfix:max "⁺" => PReduce.plus
end Notation
theorem par_triangle {m n : Γ ⊢ a} : (m ⇛ n) → (n ⇛ m⁺) := open PReduce in by
intro
| .var => exact .var
| .lamβ pn pv => exact subst_par (par_subst₁σ (par_triangle pv)) (par_triangle pn)
| .lamζ pn => exact lamζ (par_triangle pn)
| .apξ pl pm => rename_i l l' m m'; match l with
| ` _ => exact apξ (par_triangle pl) (par_triangle pm)
| _ □ _ => exact apξ (par_triangle pl) (par_triangle pm)
| ƛ _ => have .lamζ pl := pl; exact lamβ (par_triangle pl) (par_triangle pm)
theorem par_diamond {m n n' : Γ ⊢ a} (p : m ⇛ n) (p' : m ⇛ n')
: ∃ (l : Γ ⊢ a), (n ⇛ l) ∧ (n' ⇛ l)
:= by
exists m⁺; constructor <;> (apply par_triangle; trivial)
-- https://plfa.github.io/Confluence/#proof-of-confluence-for-parallel-reduction
theorem strip {m n n' : Γ ⊢ a} (mn : m ⇛ n) (mn' : m ⇛* n')
: ∃ (l : Γ ⊢ a), (n ⇛* l) ∧ (n' ⇛ l)
:= by induction mn' using head_induction_on generalizing n with
| refl => exists n, .refl
| head mm' _ r =>
rename_i m' f; have ⟨l, hl⟩ := r (par_triangle mm')
exists l; refine ⟨?_, hl.2⟩; exact .trans (par_triangle mn) hl.1
theorem par_confluence {l m m' : Γ ⊢ a} (lm : l ⇛* m) (lm' : l ⇛* m')
: ∃ (n : Γ ⊢ a), (m ⇛* n) ∧ (m' ⇛* n)
:= by induction lm using head_induction_on generalizing m' with
| refl => exists m', lm'
| head lm₁ _ r =>
have ⟨n, m₁n, m'n⟩ := strip lm₁ lm'
have ⟨n', mn', nn'⟩ := r m₁n
exists n', mn'; exact .trans m'n nn'
-- https://plfa.github.io/Confluence/#proof-of-confluence-for-reduction
theorem confluence {l m m' : Γ ⊢ a} (lm : l —↠ m) (lm' : l —↠ m')
: ∃ (n : Γ ⊢ a), (m —↠ n) ∧ (m' —↠ n)
:= by
let equiv := @instNonemptyPReduceReduceClos Γ a
have ⟨n, mn, m'n⟩:= par_confluence (equiv.invFun lm) (equiv.invFun lm')
exists n; exact ⟨equiv.toFun mn, equiv.toFun m'n⟩