Skip to content

Commit a2033fa

Browse files
committed
Prove that successful parsing produces exactly one output element
1 parent 08d443f commit a2033fa

File tree

1 file changed

+67
-21
lines changed

1 file changed

+67
-21
lines changed

HumanEvalLean/HumanEval160.lean

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,10 @@ structure ParseState where
6969

7070
namespace ParseState
7171

72+
@[simp]
7273
def pushArg (σ : ParseState) (arg : Nat) : ParseState :=
7374
{ σ with output := (lit arg) :: σ.output }
7475

75-
@[simp]
76-
theorem pushArg_ops (σ : ParseState) : (σ.pushArg arg).ops = σ.ops := rfl
77-
7876
def pushOp? (σ : ParseState) (op : Op) : Option ParseState :=
7977
match σ.hold with
8078
| [] => some { σ with hold := [op] }
@@ -95,37 +93,85 @@ theorem pushOp?_ops {σ : ParseState} (h : σ.pushOp? op = some σ') : σ'.ops =
9593
| injection h with h; rw [←h]
9694
| contradiction
9795

96+
theorem pushOp?_output_hold_length
97+
{σ₁ : ParseState} (hp : σ₁.pushOp? op = some σ₂) (hl : σ₁.hold.length < σ₁.output.length) :
98+
σ₂.output.length - σ₂.hold.length = σ₁.output.length - σ₁.hold.length - 1 := by
99+
rw [pushOp?] at hp
100+
(repeat' split at hp) <;> injection hp
101+
all_goals next hp => simp_all only [List.length_cons, ←hp]; omega
102+
103+
theorem pushOp?_hold_length_le_output_length
104+
{σ₁ : ParseState} (hp : σ₁.pushOp? op = some σ₂) (hl : σ₁.hold.length < σ₁.output.length) :
105+
σ₂.hold.length ≤ σ₂.output.length := by
106+
rw [pushOp?] at hp
107+
(repeat' split at hp) <;> injection hp
108+
all_goals next hp => simp_all +arith [←hp]
109+
98110
def finalize (σ : ParseState) : ParseState :=
99111
match _ : σ.hold, σ.output with
100-
| op :: hold, arg₂ :: arg₁ :: out => finalize { σ with hold, output := .app op arg₁ arg₂ :: out }
112+
| op :: hold, arg₂ :: arg₁ :: out => finalize { σ with hold, output := app op arg₁ arg₂ :: out }
101113
| _, _ => σ
102114
termination_by σ.hold
103115
decreasing_by simp_all +arith
104116

117+
theorem finalize_output_length {σ : ParseState} (h : σ.hold.length < σ.output.length) :
118+
σ.finalize.output.length = σ.output.length - σ.hold.length := by
119+
replace ⟨ops, args, hold, output⟩ := σ
120+
induction hold generalizing output <;> cases output <;> rw [finalize]
121+
case cons.cons out => cases out <;> simp_all
122+
all_goals simp_all
123+
124+
def run (σ : ParseState) : Option ParseState :=
125+
match _ : σ.ops, σ.args with
126+
| op :: ops, arg :: args =>
127+
match _ : { σ with ops, args } |>.pushArg arg |>.pushOp? op with
128+
| none => none
129+
| some σ => run σ
130+
| [], [arg] => { σ with args := [] } |>.pushArg arg |>.finalize
131+
| _, _ => none
132+
termination_by σ.ops
133+
decreasing_by simp_all +arith [pushOp?_ops ‹_›]
134+
135+
theorem run_output_length
136+
{σ₁ : ParseState} (hr : σ₁.run = some σ₂) (hl : σ₁.hold.length ≤ σ₁.output.length) :
137+
σ₂.output.length = σ₁.output.length + 1 - σ₁.hold.length := by
138+
rw [run] at hr
139+
repeat' split at hr
140+
· contradiction
141+
next σ' h =>
142+
have : σ'.ops.length < σ₁.ops.length := by simp [pushOp?_ops h, *]
143+
have hl := pushOp?_hold_length_le_output_length h <| by simp_all +arith
144+
rw [run_output_length hr hl]
145+
have := pushOp?_output_hold_length h <| by simp only [pushArg, List.length_cons]; omega
146+
simp only [pushArg, List.length_cons] at this
147+
omega
148+
· injection hr with hr
149+
rw [←hr, finalize_output_length]
150+
repeat simp only [pushArg, List.length_cons]
151+
omega
152+
· contradiction
153+
termination_by σ₁.ops.length
154+
155+
-- This implies that `parse?` either fails, or returns precisely the single output element.
156+
theorem run_output_singleton {ops args} (h : run { ops, args } = some σ) : σ.output.length = 1 :=
157+
run_output_length h .refl
158+
105159
end ParseState
106160

107161
-- Parses an expression based on the "shunting yard algorithm".
108162
def parse? (ops : List Op) (args : List Nat) : Option Expr :=
109-
go { ops, args } >>= (·.output[0]?)
110-
where
111-
go (σ : ParseState) : Option ParseState :=
112-
match _ : σ.ops, σ.args with
113-
| op :: ops, arg :: args =>
114-
match _ : { σ with ops, args } |>.pushArg arg |>.pushOp? op with
115-
| none => none
116-
| some σ => go σ
117-
| [], [arg] => { σ with args := [] } |>.pushArg arg |>.finalize
118-
| _, _ => none
119-
termination_by σ.ops
120-
decreasing_by simp_all +arith [ParseState.pushOp?_ops ‹_›]
121-
122-
theorem parse?.some_iff : (parse? ops args = some e) ↔ (args.length = ops.length + 1) := by
123-
sorry
163+
match h : { ops, args : ParseState }.run with
164+
| none => none
165+
| some σ => σ.output[0]'(by simp [ParseState.run_output_singleton h])
166+
167+
theorem parse?_isSome_iff : (parse? ops args).isSome ↔ (args.length = ops.length + 1) where
168+
mp := sorry
169+
mpr := sorry
124170

125-
theorem parse?.lits_eq_args (h : parse? ops args = some e) : e.lits = args := by
171+
theorem parse?_lits_eq_args (h : parse? ops args = some e) : e.lits = args := by
126172
sorry
127173

128-
theorem parse?.apps_eq_ops (h : parse? ops args = some e) : e.apps = ops := by
174+
theorem parse?_apps_eq_ops (h : parse? ops args = some e) : e.apps = ops := by
129175
sorry
130176

131177
end Expr

0 commit comments

Comments
 (0)