File: euler002.mlw

package info (click to toggle)
why3 1.8.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 45,028 kB
  • sloc: xml: 185,443; ml: 111,224; ansic: 3,998; sh: 2,578; makefile: 2,568; java: 865; python: 720; javascript: 290; lisp: 205; pascal: 173
file content (112 lines) | stat: -rw-r--r-- 2,769 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
(* Euler Project, problem 2

Each new term in the Fibonacci sequence is generated by adding the
previous two terms. By starting with 1 and 2, the first 10 terms will
be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

By considering the terms in the Fibonacci sequence whose values do not
exceed four million, find the sum of the even-valued terms. *)

(** {2 Sum of even-valued Fibonacci numbers} *)

theory FibSumEven

  use int.Int
  use int.Fibonacci
  use int.ComputerDivision

  (* [fib_sum_even m n] is the sum of even-valued terms of the
      Fibonacci sequence from index 0 to n-1, that do not exceed m *)
  function fib_sum_even int int : int

  axiom SumZero: forall m:int. fib_sum_even m 0 = 0

  axiom SumEvenLe: forall n m:int.
     n >= 0 -> fib n <= m -> mod (fib n) 2 = 0 ->
       fib_sum_even m (n+1) = fib_sum_even m n + fib n

  axiom SumEvenGt: forall n m:int.
     n >= 0 -> fib n > m -> mod (fib n) 2 = 0 ->
       fib_sum_even m (n+1) = fib_sum_even m n

  axiom SumOdd: forall n m:int.
     n >= 0 -> mod (fib n) 2 <> 0 ->
       fib_sum_even m (n+1) = fib_sum_even m n

  predicate is_fib_sum_even (m:int) (sum:int) =
    exists n:int.
      sum = fib_sum_even m n /\ fib n > m
   (* Note: we take for granted that [fib] is an
        increasing sequence *)

end

module FibOnlyEven

  use int.Int
  use int.ComputerDivision
  use int.Fibonacci

  let rec lemma fib_even_3n (n:int)
    requires { n >= 0 }
    variant { n }
    ensures { mod (fib n) 2 = 0 <-> mod n 3 = 0 }
  = if n > 2 then fib_even_3n (n-3)

  function fib_even (n: int) : int = fib (3 * n)

  lemma fib_even0: fib_even 0 = 0
  lemma fib_even1: fib_even 1 = 2

  lemma fib_evenn: forall n:int [fib_even n].
     n >= 2 -> fib_even n = 4 * fib_even (n-1) + fib_even (n-2)

end

module Solve

  use int.Int
  use ref.Ref
  use int.Fibonacci
  use FibSumEven
  use FibOnlyEven

  let f m : int
    requires { m >= 0 }
    ensures  { exists n:int. result = fib_sum_even m n /\ fib n > m }
  = let x = ref 0 in
    let y = ref 2 in
    let sum = ref 0 in
    let ghost n = ref 0 in
    let ghost k = ref 0 in
    while !x <= m do
      invariant { !n >= 0 }
      invariant { !k >= 0 }
      invariant { !x = fib_even !n }
      invariant { !x = fib !k }
      invariant { !y = fib_even (!n+1) }
      invariant { !y = fib (!k+3) }
      invariant { !sum = fib_sum_even m !k }
      invariant { 0 <= !x < !y }
      variant { m - !x }
      let tmp = !x in
      x := !y;
      y := 4 * !y + tmp;
      sum := !sum + tmp;
      n := !n + 1;
      k := !k + 3
    done;
    !sum

  let run () = f 4_000_000 (* should be 4613732 *)

  exception BenchFailure

  let bench () raises { BenchFailure -> true } =
    let x = run () in
    if x <> 4613732 then raise BenchFailure;
    x

end