sbv-0.9.18: Symbolic Bit Vectors: Prove bit-precise program properties using SMT solvers.

Portability portable experimental erkokl@gmail.com

Data.SBV.Examples.CodeGeneration.Fibonacci

Description

Computing Fibonacci numbers and generating C code. Inspired by Lee Pike's original implementation, modified for inclusion in the package. It illustrates symbolic termination issues one can have when working with recursive algorithms and how to deal with such, eventually generating good C code.

Synopsis

# A naive implementation

This is a naive implementation of fibonacci, and will work fine (albeit slow) for concrete inputs:

````>>> ````map fib0 [0..6]
```[0 :: SWord32,1 :: SWord32,1 :: SWord32,2 :: SWord32,3 :: SWord32,5 :: SWord32,8 :: SWord32]
```

However, it is not suitable for doing proofs or generating code, as it is not symbolically terminating when it is called with a symbolic value `n`. When we recursively call `fib0` on `n-1` (or `n-2`), the test against `0` will always explore both branches since the result will be symbolic, hence will not terminate. (An integrated theorem prover can establish termination after a certain number of unrollings, but this would be quite expensive to implement, and would be impractical.)

# Using a recursion depth, and accumulating parameters

One way to deal with symbolic termination is to limit the number of recursive calls. In this version, we impose a limit on the index to the function, working correctly upto that limit. If we use a compile-time constant, then SBV's code generator can produce code as the unrolling will eventually stop.

The recursion-depth limited version of fibonacci. Limiting the maximum number to be 20, we can say:

````>>> ````map (fib1 20) [0..6]
```[0 :: SWord32,1 :: SWord32,1 :: SWord32,2 :: SWord32,3 :: SWord32,5 :: SWord32,8 :: SWord32]
```

The function will work correctly, so long as the index we query is at most `top`, and otherwise will return the value at `top`. Note that we also use accumulating parameters here for efficiency, although this is orthogonal to the termination concern.

We can generate code for `fib1` using the `genFib1` action. Note that the generated code will grow larger as we pick larger values of `top`, but only linearly, thanks to the accumulating parameter trick used by `fib1`. The following is an excerpt from the code generated for the call `genFib1 10`, where the code will work correctly for indexes up to 10:

``` SWord32 fib1(const SWord32 x)
{
const SWord32 s0 = x;
const SBool   s2 = s0 == 0x00000000UL;
const SBool   s4 = s0 == 0x00000001UL;
const SBool   s6 = s0 == 0x00000002UL;
const SBool   s8 = s0 == 0x00000003UL;
const SBool   s10 = s0 == 0x00000004UL;
const SBool   s12 = s0 == 0x00000005UL;
const SBool   s14 = s0 == 0x00000006UL;
const SBool   s17 = s0 == 0x00000007UL;
const SBool   s19 = s0 == 0x00000008UL;
const SBool   s22 = s0 == 0x00000009UL;
const SWord32 s25 = s22 ? 0x00000022UL : 0x00000037UL;
const SWord32 s26 = s19 ? 0x00000015UL : s25;
const SWord32 s27 = s17 ? 0x0000000dUL : s26;
const SWord32 s28 = s14 ? 0x00000008UL : s27;
const SWord32 s29 = s12 ? 0x00000005UL : s28;
const SWord32 s30 = s10 ? 0x00000003UL : s29;
const SWord32 s31 = s8 ? 0x00000002UL : s30;
const SWord32 s32 = s6 ? 0x00000001UL : s31;
const SWord32 s33 = s4 ? 0x00000001UL : s32;
const SWord32 s34 = s2 ? 0x00000000UL : s33;

return s34;
}
```

# Generating a look-up table

While `fib1` generates good C code, we can do much better by taking advantage of the inherent partial-evaluation capabilities of SBV to generate a look-up table, as follows.

Compute the fibonacci numbers statically at code-generation time and put them in a table, accessed by the `select` call.

Once we have `fib2`, we can generate the C code straightforwardly. Below is an excerpt from the code that SBV generates for the call `genFib2 64`. Note that this code is a constant-time look-up table implementation of fibonacci, with no run-time overhead. The index can be made arbitrarily large, naturally. (Note that this function returns `0` if the index is larger than 64, as specified by the call to `select` with default `0`.)

``` SWord32 fibLookup(const SWord32 x)
{
const SWord32 s0 = x;
static const SWord32 table0[] = {
0x00000000UL, 0x00000001UL, 0x00000001UL, 0x00000002UL,
0x00000003UL, 0x00000005UL, 0x00000008UL, 0x0000000dUL,
0x00000015UL, 0x00000022UL, 0x00000037UL, 0x00000059UL,
0x00000090UL, 0x000000e9UL, 0x00000179UL, 0x00000262UL,
0x000003dbUL, 0x0000063dUL, 0x00000a18UL, 0x00001055UL,
0x00001a6dUL, 0x00002ac2UL, 0x0000452fUL, 0x00006ff1UL,
0x0000b520UL, 0x00012511UL, 0x0001da31UL, 0x0002ff42UL,
0x00213d05UL, 0x0035c7e2UL, 0x005704e7UL, 0x008cccc9UL,
0x00e3d1b0UL, 0x01709e79UL, 0x02547029UL, 0x03c50ea2UL,
0x06197ecbUL, 0x09de8d6dUL, 0x0ff80c38UL, 0x19d699a5UL,
0x29cea5ddUL, 0x43a53f82UL, 0x6d73e55fUL, 0xb11924e1UL,
0x1e8d0a40UL, 0xcfa62f21UL, 0xee333961UL, 0xbdd96882UL,