1- def find_max : Unit :=
2- ()
1+ import Lean
2+ open Std
3+
4+ def String.numUniqueChars (str : String) : Nat :=
5+ str.foldl (·.insert) (∅ : HashSet _) |>.size
6+
7+ def findMax (strs : List String) : Option String :=
8+ strs.foldl (max? · ·) none
9+ where
10+ max? : Option String → String → String
11+ | none, str => str
12+ | some str₁, str₂ => max str₁ str₂
13+ max (str₁ str₂ : String) : String :=
14+ match compare str₁.numUniqueChars str₂.numUniqueChars with
15+ | .gt => str₁
16+ | .lt => str₂
17+ | .eq => if str₁ < str₂ then str₁ else str₂
18+
19+ example : findMax ["name" , "of" , "string" ] = "string" := by native_decide
20+ example : findMax ["name" , "enam" , "game" ] = "enam" := by native_decide
21+ example : findMax ["aaaaaaa" , "bb" ,"cc" ] = "aaaaaaa" := by native_decide
22+ example : findMax ["name" , "of" , "string" ] = "string" := by native_decide
23+ example : findMax ["name" , "enam" , "game" ] = "enam" := by native_decide
24+ example : findMax ["aaaaaaa" , "bb" , "cc" ] = "aaaaaaa" := by native_decide
25+ example : findMax ["abc" , "cba" ] = "abc" := by native_decide
26+ example : findMax ["play" , "this" , "game" , "of" ,"footbott" ] = "footbott" := by native_decide
27+ example : findMax ["we" , "are" , "gonna" , "rock" ] = "gonna" := by native_decide
28+ example : findMax ["we" , "are" , "a" , "mad" , "nation" ] = "nation" := by native_decide
29+ example : findMax ["this" , "is" , "a" , "prrk" ] = "this" := by native_decide
30+ example : findMax ["b" ] = "b" := by native_decide
31+ example : findMax ["play" , "play" , "play" ] = "play" := by native_decide
32+
33+ theorem findMax_mem (h : findMax strs = some m) : m ∈ strs := by
34+ induction strs generalizing m <;> rw [findMax] at h
35+ case nil => contradiction
36+ case cons ih =>
37+ simp [findMax.max?] at h
38+ sorry -- Problem: We can't use IH again, cause we haven't generalized over the fold's init.
39+ -- Can we use `List.foldl_hom`?
40+
41+ theorem findMax_cons : findMax (hd :: tl) = findMax.max? (findMax tl) hd := by
42+ sorry
43+
44+ -- TODO: Does this actually hold? If not, use some sort of lex compare function instead of `<`.
45+ theorem String.le_of_lt {s₁ s₂ : String} (h : s₁ < s₂) : s₁ ≤ s₂ :=
46+ sorry
47+
48+ structure UniqueMax (max : String) (strs : List String) : Prop where
49+ mem : max ∈ strs
50+ max_unique : ∀ str ∈ strs, str.numUniqueChars ≤ max.numUniqueChars
51+ min_lex : ∀ str ∈ strs, str.numUniqueChars = max.numUniqueChars → max ≤ str
52+
53+ namespace UniqueMax
54+
55+ theorem tail (h : UniqueMax m (hd :: tl)) (hm : m ∈ tl) : UniqueMax m tl where
56+ mem := hm
57+ max_unique _ hm := h.max_unique _ (.tail _ hm)
58+ min_lex _ hm := h.min_lex _ (.tail _ hm)
59+
60+ theorem to_findMax_max (h : UniqueMax m strs) (hm : str ∈ strs) : findMax.max m str = m := by
61+ rw [findMax.max]
62+ split <;> (try split) <;> try rfl
63+ next hc =>
64+ rw [Nat.compare_eq_lt] at hc
65+ have := h.max_unique _ hm
66+ omega
67+ next hc hl =>
68+ rw [Nat.compare_eq_eq] at hc
69+ have := h.min_lex _ hm hc.symm
70+ exact String.le_antisymm hl this
71+
72+ theorem to_findMax (h : UniqueMax m strs) : findMax strs = m := by
73+ induction strs <;> cases h.mem
74+ case cons.tail ih hm => simp [findMax_cons, ih (h.tail hm), findMax.max?, h.to_findMax_max]
75+ case cons.head tl ih =>
76+ simp only [findMax_cons, findMax.max?, findMax.max]
77+ split <;> (try split) <;> (try split) <;> try rfl
78+ next hf _ hc =>
79+ rw [Nat.compare_eq_gt] at hc
80+ have := h.max_unique _ (.tail _ <| findMax_mem hf)
81+ omega
82+ next hf _ hc hl =>
83+ rw [Nat.compare_eq_eq] at hc
84+ have := h.min_lex _ (.tail _ <| findMax_mem hf) hc
85+ simp [String.le_antisymm (String.le_of_lt hl) this]
86+
87+ theorem of_findMax (h : findMax strs = some m) : UniqueMax m strs where
88+ mem := findMax_mem h
89+ max_unique str hm := by
90+ induction strs
91+ case nil => sorry
92+ case cons ih => sorry -- Same problem in IH as with `findMax_mem` above.
93+ min_lex := sorry -- Probably by induction with the same problem as commented on above.
94+
95+ theorem iff_findMax : (UniqueMax m strs) ↔ (findMax strs = m) where
96+ mp := to_findMax
97+ mpr := of_findMax
98+
99+ end UniqueMax
3100
4101/-!
5102## Prompt
@@ -44,4 +141,4 @@ def check(candidate):
44141 assert (candidate(["play", "play", "play"]) == "play"), 't10'
45142
46143```
47- -/
144+ -/
0 commit comments