11module
22
3- def fibfib : Unit :=
4- ()
3+ public import Std
4+ open Std Std.Do
5+
6+ set_option mvcgen.warning false
7+
8+ /-!
9+ ## Implementation
10+
11+ (See also problem 46.)
12+ -/
13+
14+ def fibfib (n : Nat) : Nat := Id.run do
15+ let mut lastThree : Vector Nat 3 := #v[0 , 0 , 1 ]
16+ for i in *...(n - 2 ) do
17+ lastThree := lastThree.set (i % 3 ) (lastThree[0 ] + lastThree[1 ] + lastThree[2 ])
18+ return lastThree[n % 3 ]
19+
20+ /-! ## Tests -/
21+
22+ example : fibfib 2 = 1 := by native_decide
23+ example : fibfib 1 = 0 := by native_decide
24+ example : fibfib 5 = 4 := by native_decide
25+ example : fibfib 8 = 24 := by native_decide
26+ example : fibfib 10 = 81 := by native_decide
27+ example : fibfib 12 = 274 := by native_decide
28+ example : fibfib 14 = 927 := by native_decide
29+
30+ /-! ## Missing API -/
31+
32+ theorem eq_getElem_append_cons {pref suff : List α} {cur : α} :
33+ (pref ++ cur :: suff)[pref.length]? = cur := by
34+ simp
35+
36+ grind_pattern eq_getElem_append_cons => pref ++ cur :: suff
37+ attribute [grind =] Nat.getElem?_toList_rio
38+ attribute [grind =] Nat.length_toList_rio
39+
40+ /-! ## Verification -/
41+
42+ def fibfibReference : Nat → Nat
43+ | 0 => 0
44+ | 1 => 0
45+ | 2 => 1
46+ | k + 3 =>
47+ fibfibReference (k + 2 ) + fibfibReference (k + 1 ) + fibfibReference k
48+
49+ theorem sum_mod_eq_sum {vec : Vector Nat 3 } :
50+ ∀ i, vec[i % 3 ] + vec[(i + 1 ) % 3 ] + vec[(i + 2 ) % 3 ] =
51+ vec[0 ] + vec[1 ] + vec[2 ]
52+ | 0 | 1 | 2 => by grind
53+ | i + 3 => by
54+ have := sum_mod_eq_sum (vec := vec) (i := i)
55+ simp only [Nat.add_mod_right]
56+ grind
57+
58+ theorem fibfib_eq_fibfibReference :
59+ fibfib n = fibfibReference n := by
60+ generalize hwp : fibfib n = wp
61+ apply Id.of_wp_run_eq hwp
62+ mvcgen
63+ invariants
64+ · ⇓⟨cur, lastThree⟩ => ⌜∀ i, i < 3 → lastThree[(cur.pos + i) % 3 ] = fibfibReference (cur.pos + i)⌝
65+ case vc1 pref cur suff heq _ _ h =>
66+ simp_all only [List.Cursor.pos_mk, List.length_append, List.length_cons, List.length_nil]
67+ intro i hi
68+ by_cases i = 2
69+ · rename_i hi'
70+ rw [hi', fibfibReference]
71+ simp only [show (pref.length + 1 + 2 ) % 3 = cur % 3 by grind]
72+ grind [sum_mod_eq_sum, h 0 (by grind), h 1 (by grind), h 2 (by grind),
73+ Vector.getElem_set_self]
74+ · specialize h (i + 1 ) (by grind)
75+ grind
76+ case vc2 =>
77+ simp only [List.Cursor.pos_mk, Vector.getElem_eq_iff]
78+ decide
79+ case vc3 h =>
80+ by_cases hn : n < 3
81+ · grind
82+ · specialize h 2 (by grind)
83+ grind
584
685/-!
786## Prompt
@@ -55,4 +134,4 @@ def check(candidate):
55134 assert candidate(14) == 927
56135
57136```
58- -/
137+ -/
0 commit comments