6 lemma isfib_2_1 : fib 2 = 1
7 lemma isfib_6_8 : fib 6 = 8
9 lemma not_isfib_2_2 : fib 2 <> 2
13 module FibonacciLinear
21 ensures { fib n = result}
25 invariant { 0 <= i <= n /\ fib (i+1) = !x /\ fib i = !y }
34 module FibonacciTailRecList
42 let rec ghost function sum_fib (l:list int) : int
43 requires { forall n. mem n l -> n >= 0 }
47 | Cons x r -> fib x + sum_fib r
50 let rec ghost function sum_pow (l:list int) : int
51 requires { forall n. mem n l -> n >= 0 }
52 ensures { result >= 0 }
56 | Cons x r -> assert { mem x l };
57 assert { forall n. mem n r -> mem n l };
61 lemma pow_pos : forall x. x >= 0 -> power 3 x > 0
63 let rec sum_fib_acc (acc:int) (l:list int) : int
64 requires { forall n. mem n l -> n >= 0 }
66 ensures { result = acc + sum_fib l }
71 if n <= 1 then sum_fib_acc (acc + n) r
73 let l1 = Cons (n-2) r in
74 assert { forall u. mem u l1 -> u >= 0 };
75 let l2 = Cons (n-1) l1 in
76 assert { forall u. mem u l2 -> u >= 0 };
83 ensures { result = fib n }
85 sum_fib_acc 0 (Cons n Nil)
89 (** {2 Recursive version, using ghost code} *)
96 let rec fib_aux (ghost n: int) (a b k: int) : int
98 requires { 0 <= n && a = fib n && b = fib (n+1) }
100 ensures { result = fib (n+k) }
101 = if k = 0 then a else fib_aux (n+1) b (a+b) (k-1)
103 let fib (n: int) : int
105 ensures { result = fib n }
108 let test42 () = fib 42
110 exception BenchFailure
112 let bench () raises { BenchFailure } =
113 if test42 () <> 267914296 then raise BenchFailure
117 (** {2 Recursive version, without ghost code} *)
124 let rec fib_aux (a b k: int) : int
126 requires { exists n: int. 0 <= n && a = fib n && b = fib (n+1) }
128 ensures { forall n: int. 0 <= n && a = fib n && b = fib (n+1) ->
130 = if k = 0 then a else fib_aux b (a+b) (k-1)
132 let fib (n: int) : int
134 ensures { result = fib n }
139 module SmallestFibAbove
146 let smallest_fib_above (x: int) : int
148 ensures { exists k. 0 <= k /\ fib k <= x < fib (k+1) = result }
152 let ghost k = ref 0 in
154 invariant { 0 <= !k /\ !a = fib !k <= x /\ !b = fib (!k+1) }
155 invariant { 0 <= !a /\ 1 <= !b }
156 variant { 2*x - (!a + !b) }
167 Zeckendorf's theorem states that every positive integer can be
168 represented uniquely as the sum of one or more distinct Fibonacci
169 numbers in such a way that the sum does not include any two
170 consecutive Fibonacci numbers.
172 Cf https://en.wikipedia.org/wiki/Zeckendorf%27s_theorem
184 function sum (l: list int) : int = match l with
186 | Cons k r -> fib k + sum r
189 (* sorted in increasing order, above min, and non consecutive *)
190 predicate wf (min: int) (l: list int) = match l with
192 | Cons k r -> min <= k /\ wf (k + 2) r
195 let rec lemma fib_nonneg (n: int) : unit
197 ensures { 0 <= fib n }
199 = if n > 1 then begin fib_nonneg (n-2); fib_nonneg (n-1) end
201 let rec lemma fib_increasing (k1 k2: int) : unit
202 requires { 0 <= k1 <= k2 }
203 ensures { fib k1 <= fib k2 }
205 = if k1 < k2 then fib_increasing (k1+1) k2
207 let greatest_fib (x: int) : (int, int)
209 ensures { let k, fk = result in
210 2 <= k /\ 1 <= fk = fib k <= x < fib (k + 1) }
216 invariant { 1 <= !k /\ !a = fib !k <= x /\ !b = fib (!k + 1) }
217 invariant { 1 <= !a /\ 1 <= !b }
218 variant { 2*x - (!a + !b) }
226 let zeckendorf (n: int) : list int
228 ensures { wf 2 result }
229 ensures { n = sum result }
234 invariant { 0 <= !x <= n }
235 invariant { wf 2 !l }
236 invariant { !x + sum !l = n }
237 invariant { match !l with Nil -> true | Cons k _ -> !x < fib (k-1) end }
239 let k, fk = greatest_fib !x in
245 (* a more efficient, linear implementation *)
247 let zeckendorf_fast (n: int) : list int
249 ensures { wf 2 result }
250 ensures { n = sum result }
252 if n = 0 then Nil else
257 invariant { 1 <= !k /\ !a = fib !k <= n /\ !b = fib (!k + 1) }
258 invariant { 1 <= !a /\ 1 <= !b }
259 variant { 2*n - (!a + !b) }
265 assert { 2 <= !k /\ 1 <= !a = fib !k <= n < fib (!k + 1) = !b };
266 let l = ref (Cons !k Nil) in
267 let x = ref (n - !a) in
269 invariant { 1 <= !k /\ !a = fib !k <= n /\ !x < !b = fib (!k + 1) }
270 invariant { 1 <= !a /\ 1 <= !b }
271 invariant { 0 <= !x <= n }
272 invariant { wf 2 !l }
273 invariant { !x + sum !l = n }
274 invariant { match !l with Nil -> true | Cons k _ -> !x < fib (k-1) end }
276 if !a <= !x then begin
289 function snoc (l:list int) (x:int) : list int = match l with
291 | Cons y q -> Cons y (snoc q x)
294 let rec lemma zeckendorf_unique (l1 l2:list int) : unit
295 requires { wf 2 l1 /\ wf 2 l2 }
296 requires { sum l1 = sum l2 }
299 = let rec decomp (k acc:int) (lc lb:list int) : (x: int, p: list int)
301 requires { k >= 2 /\ lc <> Nil }
302 requires { 0 <= acc = sum lb - sum lc < fib (k-1) }
303 ensures { fib x <= sum lb = acc + fib x + sum p < fib (x+1) }
304 ensures { wf k p /\ x >= k /\ lc = snoc p x }
308 | Cons x Nil -> x,Nil
309 | Cons x q -> let y,p = decomp (x+2) (acc+fib x) q lb in y,Cons x p
313 | Nil , l | l , Nil -> let _ = decomp 2 0 l l in absurd
314 | _ , _ -> let _,q1 = decomp 2 0 l1 l1 in
315 let _,q2 = decomp 2 0 l2 l2 in
316 zeckendorf_unique q1 q2
321 (** {2 2x2 integer matrices} *)
327 type t = { a11: int; a12: int; a21: int; a22: int }
329 constant id : t = { a11 = 1; a12 = 0; a21 = 0; a22 = 1 }
331 function mult (x: t) (y: t) : t =
333 a11 = x.a11 * y.a11 + x.a12 * y.a21; a12 = x.a11 * y.a12 + x.a12 * y.a22;
334 a21 = x.a21 * y.a11 + x.a22 * y.a21; a22 = x.a21 * y.a12 + x.a22 * y.a22;
338 int.Exponentiation with
339 type t = t, function one = id, function (*) = mult,
340 goal Assoc, goal Unit_def_l, goal Unit_def_r,
341 axiom . (* FIXME: replace with "goal" and prove *)
345 module FibonacciLogarithmic
349 use int.ComputerDivision
352 val constant m1110 : t
353 ensures { result = { a11 = 1; a12 = 1;
356 (* computes ((1 1) (1 0))^n in O(log(n)) time
358 since it is a matrix of the shape ((a+b b) (b a)),
359 we only return the pair (a, b) *)
361 let rec logfib (n:int) variant { n }
363 ensures { let a, b = result in
364 power m1110 n = { a11 = a+b; a12 = b; a21 = b; a22 = a } }
368 assert { 0 <= div n 2 };
369 let a, b = logfib (div n 2) in
373 assert { 2 * (div n 2) = (div n 2) + (div n 2) };
378 assert { 2 * (div n 2) + 1 = (div n 2) + (div n 2) + 1 };
383 (* by induction, we easily prove that
385 (1 1)^n = (F(n+1) F(n) )
388 thus, we can compute F(n) in O(log(n)) using funtion logfib above
391 let rec lemma fib_m (n: int)
394 ensures { let p = power m1110 n in fib (n+1) = p.a11 /\ fib n = p.a21 }
395 = if n = 0 then () else fib_m (n-1)
397 let fibo n requires { n >= 0 } ensures { result = fib n } =
398 let _, b = logfib n in b
401 let test0 () = fibo 0
402 let test1 () = fibo 1
403 let test7 () = fibo 7
404 let test42 () = fibo 42
405 let test2014 () = fibo 2014
407 exception BenchFailure
409 let bench () raises { BenchFailure } =
410 if test42 () <> 267914296 then raise BenchFailure;
411 if test2014 () <> 3561413997540486142674781564382874188700994538849211456995042891654110985470076818421080236961243875711537543388676277339875963824466334432403730750376906026741819889036464401788232213002522934897299928844192803507157647764542466327613134605502785287441134627457615461304177503249289874066244145666889138852687147544158443155204157950294129177785119464446668374163746700969372438526182906768143740891051274219441912520127
412 then raise BenchFailure