diff --git a/HumanEvalLean/HumanEval158.lean b/HumanEvalLean/HumanEval158.lean index 412562e..4cb89c2 100644 --- a/HumanEvalLean/HumanEval158.lean +++ b/HumanEvalLean/HumanEval158.lean @@ -1,5 +1,102 @@ -def find_max : Unit := - () +import Lean +open Std + +def String.numUniqueChars (str : String) : Nat := + str.foldl (·.insert) (∅ : HashSet _) |>.size + +def findMax (strs : List String) : Option String := + strs.foldl (max? · ·) none +where + max? : Option String → String → String + | none, str => str + | some str₁, str₂ => max str₁ str₂ + max (str₁ str₂ : String) : String := + match compare str₁.numUniqueChars str₂.numUniqueChars with + | .gt => str₁ + | .lt => str₂ + | .eq => if str₁ < str₂ then str₁ else str₂ + +example : findMax ["name", "of", "string"] = "string" := by native_decide +example : findMax ["name", "enam", "game"] = "enam" := by native_decide +example : findMax ["aaaaaaa", "bb" ,"cc"] = "aaaaaaa" := by native_decide +example : findMax ["name", "of", "string"] = "string" := by native_decide +example : findMax ["name", "enam", "game"] = "enam" := by native_decide +example : findMax ["aaaaaaa", "bb", "cc"] = "aaaaaaa" := by native_decide +example : findMax ["abc", "cba"] = "abc" := by native_decide +example : findMax ["play", "this", "game", "of","footbott"] = "footbott" := by native_decide +example : findMax ["we", "are", "gonna", "rock"] = "gonna" := by native_decide +example : findMax ["we", "are", "a", "mad", "nation"] = "nation" := by native_decide +example : findMax ["this", "is", "a", "prrk"] = "this" := by native_decide +example : findMax ["b"] = "b" := by native_decide +example : findMax ["play", "play", "play"] = "play" := by native_decide + +theorem findMax_mem (h : findMax strs = some m) : m ∈ strs := by + induction strs generalizing m <;> rw [findMax] at h + case nil => contradiction + case cons ih => + simp [findMax.max?] at h + sorry -- Problem: We can't use IH again, cause we haven't generalized over the fold's init. + -- Can we use `List.foldl_hom`? + +theorem findMax_cons : findMax (hd :: tl) = findMax.max? (findMax tl) hd := by + sorry + +-- TODO: Does this actually hold? If not, use some sort of lex compare function instead of `<`. +theorem String.le_of_lt {s₁ s₂ : String} (h : s₁ < s₂) : s₁ ≤ s₂ := + sorry + +structure UniqueMax (max : String) (strs : List String) : Prop where + mem : max ∈ strs + max_unique : ∀ str ∈ strs, str.numUniqueChars ≤ max.numUniqueChars + min_lex : ∀ str ∈ strs, str.numUniqueChars = max.numUniqueChars → max ≤ str + +namespace UniqueMax + +theorem tail (h : UniqueMax m (hd :: tl)) (hm : m ∈ tl) : UniqueMax m tl where + mem := hm + max_unique _ hm := h.max_unique _ (.tail _ hm) + min_lex _ hm := h.min_lex _ (.tail _ hm) + +theorem to_findMax_max (h : UniqueMax m strs) (hm : str ∈ strs) : findMax.max m str = m := by + rw [findMax.max] + split <;> (try split) <;> try rfl + next hc => + rw [Nat.compare_eq_lt] at hc + have := h.max_unique _ hm + omega + next hc hl => + rw [Nat.compare_eq_eq] at hc + have := h.min_lex _ hm hc.symm + exact String.le_antisymm hl this + +theorem to_findMax (h : UniqueMax m strs) : findMax strs = m := by + induction strs <;> cases h.mem + case cons.tail ih hm => simp [findMax_cons, ih (h.tail hm), findMax.max?, h.to_findMax_max] + case cons.head tl ih => + simp only [findMax_cons, findMax.max?, findMax.max] + split <;> (try split) <;> (try split) <;> try rfl + next hf _ hc => + rw [Nat.compare_eq_gt] at hc + have := h.max_unique _ (.tail _ <| findMax_mem hf) + omega + next hf _ hc hl => + rw [Nat.compare_eq_eq] at hc + have := h.min_lex _ (.tail _ <| findMax_mem hf) hc + simp [String.le_antisymm (String.le_of_lt hl) this] + +theorem of_findMax (h : findMax strs = some m) : UniqueMax m strs where + mem := findMax_mem h + max_unique str hm := by + induction strs + case nil => sorry + case cons ih => sorry -- Same problem in IH as with `findMax_mem` above. + min_lex := sorry -- Probably by induction with the same problem as commented on above. + +theorem iff_findMax : (UniqueMax m strs) ↔ (findMax strs = m) where + mp := to_findMax + mpr := of_findMax + +end UniqueMax /-! ## Prompt @@ -44,4 +141,4 @@ def check(candidate): assert (candidate(["play", "play", "play"]) == "play"), 't10' ``` --/ \ No newline at end of file +-/