test: pge example
This commit is contained in:
parent
40129203b2
commit
607a590238
1 changed files with 373 additions and 0 deletions
373
tests/playground/pge.lean
Normal file
373
tests/playground/pge.lean
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
-- This module defines
|
||||
namespace Nat
|
||||
|
||||
-- `forallRange i n f` is true if f holds for all indices j from i to n-1.
|
||||
def forallRange (i:Nat) (n:Nat) (f: ∀ (j:Nat), j < n → Bool) : Bool :=
|
||||
if h:i < n then
|
||||
f i h && forallRange (i+1) n f
|
||||
else
|
||||
true
|
||||
termination_by forallRange i n f => n-i
|
||||
|
||||
-- `forallRange` correctness theorem.
|
||||
theorem forallRangeImplies'
|
||||
(n i j : Nat)
|
||||
(f : ∀(k:Nat), k < n → Bool)
|
||||
(eq : i+j = n)
|
||||
(p : forallRange i n f = true)
|
||||
(k : Nat)
|
||||
(lb : i ≤ k)
|
||||
(ub : k < n)
|
||||
: f k ub = true := by
|
||||
induction j generalizing i with
|
||||
| zero =>
|
||||
simp at eq
|
||||
simp [eq] at lb
|
||||
have pr := Nat.not_le_of_gt ub
|
||||
contradiction
|
||||
| succ j ind =>
|
||||
have i_lt_n : i < n := Nat.le_trans (Nat.succ_le_succ lb) ub
|
||||
unfold forallRange at p
|
||||
simp [i_lt_n] at p
|
||||
cases Nat.eq_or_lt_of_le lb with
|
||||
| inl hEq =>
|
||||
subst hEq
|
||||
apply p.1
|
||||
| inr hLt =>
|
||||
have succ_i_add_j : succ i + j = n := by simp_arith [← eq]
|
||||
apply ind (succ i) succ_i_add_j p.2 hLt
|
||||
|
||||
-- Correctness theorem for `forallRange`
|
||||
theorem forallRangeImplies (p:forallRange i n f = true) {j:Nat} (lb:i ≤ j) (ub : j < n)
|
||||
: f j ub = true :=
|
||||
have h : i+(n-i)=n := Nat.add_sub_of_le (Nat.le_trans lb (Nat.le_of_lt ub))
|
||||
forallRangeImplies' n i (n-i) f h p j lb ub
|
||||
|
||||
theorem lt_or_eq_of_succ {i j:Nat} (lt : i < Nat.succ j) : i < j ∨ i = j :=
|
||||
match lt with
|
||||
| Nat.le.step m => Or.inl m
|
||||
| Nat.le.refl => Or.inr rfl
|
||||
|
||||
-- Introduce strong induction principal for natural numbers.
|
||||
theorem strong_induction_on {p : Nat → Prop} (n:Nat)
|
||||
(h:∀n, (∀ m, m < n → p m) → p n) : p n := by
|
||||
suffices ∀n m, m < n → p m from this (succ n) n (Nat.lt_succ_self _)
|
||||
intros n
|
||||
induction n with
|
||||
| zero =>
|
||||
intros m h
|
||||
contradiction
|
||||
| succ i ind =>
|
||||
intros m h1
|
||||
cases Nat.lt_or_eq_of_succ h1 with
|
||||
| inl is_lt =>
|
||||
apply ind _ is_lt
|
||||
| inr is_eq =>
|
||||
apply h
|
||||
rw [is_eq]
|
||||
apply ind
|
||||
|
||||
end Nat
|
||||
|
||||
-- Introduce strong induction principal for Fin.
|
||||
theorem Fin.strong_induction_on {P : Fin w → Prop} (i:Fin w)
|
||||
(ind : ∀(i:Fin w), (∀(j:Fin w), j < i → P j) → P i)
|
||||
: P i := by
|
||||
cases i with
|
||||
| mk i i_lt =>
|
||||
revert i_lt
|
||||
apply @Nat.strong_induction_on (λi => ∀ (i_lt : i < w), P { val := i, isLt := i_lt })
|
||||
intros j p j_lt_w
|
||||
apply ind ⟨j, j_lt_w⟩
|
||||
intros z z_lt_j
|
||||
apply p _ z_lt_j
|
||||
|
||||
namespace PEG
|
||||
|
||||
inductive Expression (t : Type) (nt : Type) where
|
||||
| epsilon : Expression t nt
|
||||
| fail : Expression t nt
|
||||
| any : Expression t nt
|
||||
| terminal : t → Expression t nt
|
||||
| seq : (a b : nt) → Expression t nt
|
||||
| choice : (a b : nt) → Expression t nt
|
||||
| look : (a : nt) → Expression t nt
|
||||
| notP : (e : nt) → Expression t nt
|
||||
|
||||
def Grammar (t nt : Type _) := nt → Expression t nt
|
||||
|
||||
structure ProofRecord (nt : Type) where
|
||||
leftnonterminal : nt
|
||||
success : Bool
|
||||
position : Nat
|
||||
lengthofspan : Nat
|
||||
subproof1index : Nat
|
||||
subproof2index : Nat
|
||||
|
||||
namespace ProofRecord
|
||||
|
||||
def endposition {nt:Type} (r:ProofRecord nt) : Nat := r.position + r.lengthofspan
|
||||
|
||||
inductive Result where
|
||||
| fail : Result
|
||||
| success : Nat → Result
|
||||
|
||||
def record_result (r:ProofRecord nt) : Result :=
|
||||
if r.success then
|
||||
Result.success r.lengthofspan
|
||||
else
|
||||
Result.fail
|
||||
|
||||
end ProofRecord
|
||||
|
||||
def PreProof (nt : Type) := Array (ProofRecord nt)
|
||||
|
||||
def record_match [dnt : DecidableEq nt] (r:ProofRecord nt) (n:nt) (i:Nat) : Bool :=
|
||||
r.leftnonterminal = n && r.position = i
|
||||
|
||||
open Expression
|
||||
|
||||
section well_formed
|
||||
|
||||
variable {t nt : Type}
|
||||
variable [dt : DecidableEq t]
|
||||
variable [dnt : DecidableEq nt]
|
||||
variable (g : Grammar t nt)
|
||||
variable (s : Array t)
|
||||
|
||||
def well_formed_record (p : PreProof nt) (i:Nat) (i_lt : i < p.size) (r : ProofRecord nt) : Bool :=
|
||||
let n := r.leftnonterminal
|
||||
match g n with
|
||||
| epsilon => r.success ∧ r.lengthofspan = 0
|
||||
| fail => ¬ r.success
|
||||
| any =>
|
||||
if r.position < s.size then
|
||||
r.success && r.lengthofspan = 1
|
||||
else
|
||||
¬ r.success
|
||||
| terminal t =>
|
||||
if r.position < s.size && s.getD r.position t = t then
|
||||
r.success && r.lengthofspan = 1
|
||||
else
|
||||
¬ r.success
|
||||
| seq a b =>
|
||||
r.subproof1index < i &&
|
||||
let r1 := p.getD r.subproof1index r
|
||||
record_match r1 a r.position &&
|
||||
if r1.success then
|
||||
r.subproof2index < i &&
|
||||
let r2 := p.getD r.subproof2index r
|
||||
record_match r2 b r1.endposition &&
|
||||
if r2.success then
|
||||
r.success && r.endposition = r2.endposition
|
||||
else
|
||||
¬r.success
|
||||
else
|
||||
¬r.success
|
||||
| choice a b =>
|
||||
r.subproof1index < i &&
|
||||
let r1 := p.getD r.subproof1index r
|
||||
record_match r1 a r.position &&
|
||||
if r1.success then
|
||||
r.success && r.lengthofspan = r1.lengthofspan
|
||||
else
|
||||
r.subproof2index < i &&
|
||||
let r2 := p.getD r.subproof2index r
|
||||
record_match r2 b r.position &&
|
||||
if r2.success then
|
||||
r.success && r.lengthofspan = r2.lengthofspan
|
||||
else
|
||||
¬r.success
|
||||
| look a =>
|
||||
r.subproof1index < i &&
|
||||
let r1 := p.getD r.subproof1index r
|
||||
record_match r1 a r.position &&
|
||||
if r1.success then
|
||||
r.success && r.lengthofspan = 0
|
||||
else
|
||||
¬r.success
|
||||
| notP a =>
|
||||
r.subproof1index < i &&
|
||||
let r1 := p.getD r.subproof1index r
|
||||
record_match r1 a r.position &&
|
||||
if r1.success then
|
||||
¬r.success
|
||||
else
|
||||
r.success && r.lengthofspan = 0
|
||||
|
||||
|
||||
def well_formed_proof (p : PreProof nt) : Bool :=
|
||||
Nat.forallRange 0 p.size (λi lt => well_formed_record g s p i lt (p.get ⟨i, lt⟩))
|
||||
|
||||
end well_formed
|
||||
|
||||
def Proof [DecidableEq t] [DecidableEq nt] (g:Grammar t nt) (s: Array t) :=
|
||||
{ p:PreProof nt // well_formed_proof g s p }
|
||||
|
||||
namespace Proof
|
||||
|
||||
variable {g:Grammar t nt}
|
||||
variable {s : Array t}
|
||||
variable [DecidableEq t]
|
||||
variable [DecidableEq nt]
|
||||
|
||||
def size (p:Proof g s) := p.val.size
|
||||
|
||||
def get (p:Proof g s) : Fin p.size → ProofRecord nt := p.val.get
|
||||
|
||||
instance : CoeFun (Proof g s) (fun p => Fin p.size → ProofRecord nt) :=
|
||||
⟨fun p => p.get⟩
|
||||
|
||||
theorem has_well_formed_record (p:Proof g s) (i:Fin p.size) :
|
||||
well_formed_record g s p.val i.val i.isLt (p i) :=
|
||||
Nat.forallRangeImplies p.property (Nat.zero_le i.val) i.isLt
|
||||
|
||||
end Proof
|
||||
|
||||
section correctness
|
||||
|
||||
variable {g:Grammar t nt}
|
||||
variable {s : Array t}
|
||||
variable [h1:DecidableEq t]
|
||||
variable [h2:DecidableEq nt]
|
||||
|
||||
-- Lemma to rewrite from dependent use of proof index to get-with-default
|
||||
theorem proof_get_to_getD (r:ProofRecord nt) (p:Proof g s) (i:Fin p.size) :
|
||||
p i = p.val.getD i.val r := by
|
||||
have isLt : i.val < Array.size p.val := i.isLt
|
||||
simp [Proof.get, Array.get, Array.getD, isLt ]
|
||||
apply congrArg
|
||||
apply Fin.eq_of_val_eq
|
||||
trivial
|
||||
|
||||
set_option tactic.dbg_cache true
|
||||
|
||||
theorem is_deterministic
|
||||
: forall (p q : Proof g s) (i: Fin p.size) (j: Fin q.size),
|
||||
(p i).leftnonterminal = (q j).leftnonterminal
|
||||
→ (p i).position = (q j).position
|
||||
→ (p i).record_result = (q j).record_result := by
|
||||
intros p q i0
|
||||
induction i0 using Fin.strong_induction_on with
|
||||
| ind i ind =>
|
||||
intro j eq_nt p_pos_eq_q_pos
|
||||
have p_def := p.has_well_formed_record i
|
||||
have q_def := q.has_well_formed_record j
|
||||
simp only [well_formed_record, eq_nt, p_pos_eq_q_pos] at p_def q_def
|
||||
generalize q_j_eq : q j = q_j
|
||||
generalize e_eq : g (q_j.leftnonterminal) = e
|
||||
simp only [q_j_eq, e_eq] at p_def q_def p_pos_eq_q_pos
|
||||
simp only [ProofRecord.record_result]
|
||||
|
||||
cases e
|
||||
case epsilon => simp_all
|
||||
case fail => simp_all
|
||||
case any => simp at q_def; split at q_def <;> simp_all
|
||||
case terminal t => simp at q_def; split at q_def <;> simp_all
|
||||
case seq a b =>
|
||||
simp [record_match, ProofRecord.endposition] at p_def q_def
|
||||
generalize p_sub1_eq : (p i).subproof1index = p_sub1
|
||||
generalize p_sub2_eq : (p i).subproof2index = p_sub2
|
||||
generalize q_sub1_eq : q_j.subproof1index = q_sub1
|
||||
generalize q_sub2_eq : q_j.subproof2index = q_sub2
|
||||
simp only [p_sub1_eq, p_sub2_eq] at p_def
|
||||
simp only [q_sub1_eq, q_sub2_eq] at q_def
|
||||
have ⟨p_sub1_bound, ⟨p_sub1_nt, p_sub1_pos⟩, p_def⟩ := p_def
|
||||
have ⟨q_sub1_bound, ⟨q_sub1_nt, q_sub1_pos⟩, q_def⟩ := q_def
|
||||
|
||||
have ind1 := ind (Fin.mk p_sub1 (Nat.lt_trans p_sub1_bound i.isLt))
|
||||
p_sub1_bound
|
||||
(Fin.mk q_sub1 (Nat.lt_trans q_sub1_bound j.isLt))
|
||||
rw [proof_get_to_getD (p i) p, proof_get_to_getD q_j q] at ind1
|
||||
simp [ProofRecord.record_result] at ind1
|
||||
|
||||
split at p_def <;> split at q_def <;> simp [*] at ind1 p_def q_def <;> simp [*]
|
||||
|
||||
have ⟨p_sub2_bound, ⟨p_sub2_nt, p_sub2_pos⟩, p_def⟩ := p_def
|
||||
have ⟨q_sub2_bound, ⟨q_sub2_nt, q_sub2_pos⟩, q_def⟩ := q_def
|
||||
|
||||
-- Instantiate second invariant on subterm 2
|
||||
have ind2 :=
|
||||
ind (Fin.mk p_sub2 (Nat.lt_trans p_sub2_bound i.isLt))
|
||||
p_sub2_bound
|
||||
(Fin.mk q_sub2 (Nat.lt_trans q_sub2_bound j.isLt))
|
||||
rw [proof_get_to_getD (p i) p, proof_get_to_getD q_j q] at ind2
|
||||
|
||||
simp [ProofRecord.record_result] at ind2
|
||||
split at p_def <;> split at q_def <;>
|
||||
simp_arith [*] at ind2 p_def q_def <;>
|
||||
simp_arith [*]
|
||||
save
|
||||
case choice =>
|
||||
simp [record_match] at p_def q_def
|
||||
-- checkpoint simp
|
||||
generalize p_sub1_eq : (p i).subproof1index = p_sub1
|
||||
generalize p_sub2_eq : (p i).subproof2index = p_sub2
|
||||
simp only [p_sub1_eq, p_sub2_eq] at p_def
|
||||
|
||||
generalize q_sub1_eq : q_j.subproof1index = q_sub1
|
||||
generalize q_sub2_eq : q_j.subproof2index = q_sub2
|
||||
simp only [q_sub1_eq, q_sub2_eq] at q_def
|
||||
have ⟨p_sub1_bound, ⟨p_sub1_nt, p_sub1_pos⟩, p_def⟩ := p_def
|
||||
have ⟨q_sub1_bound, ⟨q_sub1_nt, q_sub1_pos⟩, q_def⟩ := q_def
|
||||
have ind1 := ind (Fin.mk p_sub1 (Nat.lt_trans p_sub1_bound i.isLt))
|
||||
p_sub1_bound
|
||||
(Fin.mk q_sub1 (Nat.lt_trans q_sub1_bound j.isLt))
|
||||
|
||||
rw [proof_get_to_getD (p i) p, proof_get_to_getD q_j q] at ind1
|
||||
simp [ProofRecord.record_result] at ind1
|
||||
save
|
||||
trace "type here"
|
||||
stop
|
||||
split at p_def <;> split at q_def <;> simp_all
|
||||
|
||||
have ⟨p_sub2_bound, ⟨p_sub2_nt, p_sub2_pos⟩, p_def⟩ := p_def
|
||||
have ⟨q_sub2_bound, ⟨q_sub2_nt, q_sub2_pos⟩, q_def⟩ := q_def
|
||||
-- Instantiate second invariant on subterm 2
|
||||
have ind2 :=
|
||||
ind (Fin.mk p_sub2 (Nat.lt_trans p_sub2_bound i.isLt))
|
||||
p_sub2_bound
|
||||
(Fin.mk q_sub2 (Nat.lt_trans q_sub2_bound j.isLt))
|
||||
rw [proof_get_to_getD (p i) p, proof_get_to_getD q_j q] at ind2
|
||||
simp [ProofRecord.record_result] at ind2
|
||||
split at p_def <;> split at q_def <;> simp_all
|
||||
stop
|
||||
case look =>
|
||||
simp [record_match] at p_def q_def
|
||||
|
||||
generalize p_sub1_eq : (p i).subproof1index = p_sub1
|
||||
simp only [p_sub1_eq] at p_def
|
||||
|
||||
generalize q_sub1_eq : q_j.subproof1index = q_sub1
|
||||
simp only [q_sub1_eq] at q_def
|
||||
have ⟨p_sub1_bound, ⟨p_sub1_nt, p_sub1_pos⟩, p_def⟩ := p_def
|
||||
have ⟨q_sub1_bound, ⟨q_sub1_nt, q_sub1_pos⟩, q_def⟩ := q_def
|
||||
|
||||
have ind1 := ind (Fin.mk p_sub1 (Nat.lt_trans p_sub1_bound i.isLt))
|
||||
p_sub1_bound
|
||||
(Fin.mk q_sub1 (Nat.lt_trans q_sub1_bound j.isLt))
|
||||
rw [proof_get_to_getD (p i) p, proof_get_to_getD q_j q] at ind1
|
||||
simp [ProofRecord.record_result] at ind1
|
||||
split at p_def <;> split at q_def <;> simp_all
|
||||
case notP =>
|
||||
simp [record_match] at p_def q_def
|
||||
|
||||
generalize p_sub1_eq : (p i).subproof1index = p_sub1
|
||||
simp only [p_sub1_eq] at p_def
|
||||
|
||||
generalize q_sub1_eq : q_j.subproof1index = q_sub1
|
||||
simp only [q_sub1_eq] at q_def
|
||||
|
||||
have ⟨p_sub1_bound, ⟨p_sub1_nt, p_sub1_pos⟩, p_def⟩ := p_def
|
||||
have ⟨q_sub1_bound, ⟨q_sub1_nt, q_sub1_pos⟩, q_def⟩ := q_def
|
||||
|
||||
have ind1 := ind (Fin.mk p_sub1 (Nat.lt_trans p_sub1_bound i.isLt))
|
||||
p_sub1_bound
|
||||
(Fin.mk q_sub1 (Nat.lt_trans q_sub1_bound j.isLt))
|
||||
rw [proof_get_to_getD (p i) p, proof_get_to_getD q_j q] at ind1
|
||||
simp [ProofRecord.record_result] at ind1
|
||||
split at p_def <;> split at q_def <;> simp_all
|
||||
|
||||
end correctness
|
||||
|
||||
end PEG
|
||||
Loading…
Add table
Reference in a new issue