Home

Programs with Proofs: Computing Fibonacci Numbers

Method of Proving

This is a program which also contains annotations to help prove its correctness using the Frama-C software.

The annotations specify various properties for a method like the pre-condition, post-condition, assertions, states modified, loop-invariants and loop-variants. They are also used to define other artifacts to ease specification/proving like predicates, logic functions, axioms and lemmas. These annotations are provided inside code-comments of the form /*@ ... */ and //@ ....

Frama-C with its WP plugin works with external provers like Alt-Ergo and CVC4 to automatically prove these specified properties. The WP plugin internally works based on the Weakest Precondition calculus. You can read more about this plugin's usage and meaning of the annotations in this tutorial.

The programs provided here have been proved using these versions of the tools: Frama-C (contains WP plugin) 21.1, Alt-Ergo 2.3.1 and CVC4 1.6. The system is x86_64 running Debian 10 Linux.

In addition to proving the specified properties, we will also be checking for other issues like overflows via another Frama-C plugin called RTE (by using option -wp-rte).

Command to prove this program:
frama-c -wp -wp-prover cvc4 -wp-rte filename.c

Computing Fibonacci Numbers


/* Method fib_recur() computes the n-th Fibonacci number F(n) using recursive calls,
   which is an inefficent approach.
   Method fib_iter() computes F(n) by iteratively computing all Fibonacci numbers
   till the n-th one.
   It is assumed that ulong has 64-bits; so the highest F(n) it can hold is F(93).
 */

typedef unsigned long ulong;

/*@
  // Inductive definition of Fibonacci numbers
  inductive fib_def(integer n, ulong f)
  {
    case base1:
      fib_def(1, (ulong)1);

    case base2:
      fib_def(2, (ulong)1);

    // read "fim1" as "F i minus 1".
    case recursion:
      \forall integer i, ulong fi, fim1; (i >= 2 && fib_def(i-1, fim1) &&
      fib_def(i, fi)) ==> fib_def(i+1, (ulong)(fim1+fi));
  }
 */

/*@
  requires 1 <= n <= 93;
  assigns \nothing;
  ensures fib_def(n, \result);
 */
ulong fib_recur(int n)
{
  if(n == 1 || n == 2)
    return 1;

  return fib_recur(n-2) + fib_recur(n-1);
}

/*@
  requires 1 <= n <= 93;
  assigns \nothing;
  ensures fib_def(n, \result);
 */
ulong fib_iter(int n)
{
  int i;
  ulong fi, fim1; /* read "fim1" as "F i minus 1" */

  if(n == 1 || n == 2)
    return 1;

  i = 2;
  fim1 = 1;
  fi = 1;

  /*@
    loop assigns i, fi, fim1;
    loop invariant 2 <= i <= n;
    loop invariant fib_def(i, fi) && fib_def(i-1, fim1);
    loop variant n - i;
   */
  while(i < n)
  {
    ulong newfi = fim1 + fi;
    fim1 = fi;
    fi = newfi;
    i = i + 1;
  }

  return fi;
}