ravencheck 0.5.0

Decidable verification of Rust code using relational abstraction.
Documentation
Here is an overview of how SMT queries are formed from `#[verify]`
conditions.

# Original query

```
fn add_twice(a: Nat, b: Nat) -> Nat {
    if b == Nat::Z {
        a
    } else {
        add(add(a, b), b)
    }
}

#[verify]
fn add_twice_monotonic() -> bool {
    !exists(|x: Nat, y: Nat| {
        gt(x, add_twice(x,y))
    })
}
```

# 1. Convert to CBPV

Ravencheck's internal representation
is Call-By-Push-Value style.
The conversion from surface-level Rust sytnax
is implemented in `lang/src/rir/from_syn.rs`.

The converted query example here
is written out using Rust syntax,
but internally Ravencheck uses the AST 
defined in `lang/src/rir/ast.rs`
to represent the code.
The AST is defined by the mutually-inductive
`Comp` and `Val` enum types.

```
fn add_twice(a: Nat, b: Nat) -> Nat {
    let v0 = b == Nat::Z;
    if v0 {
        return a
    } else {
        let v1 = add(a, b);
        let v2 = add(v1, b);
        return v2
    }
}

#[verify]
fn add_twice_monotonic() -> bool {
    let v3 = exists(|x: Nat, y: Nat| {
        let v4 = add_twice(x,y);
        let v5 = gt(x, v4);
        return v5
    });
    let v6 = !v3;
    return v6
}
```

# 2. Partial evaluaion

In this step, queries are evaluated as much as possible,
leaving only symbolic values and functions.
In this example, the `add_twice` function 
is eliminated by inlining.
In contrast, calls 
to the primitive/uninterpreted `add` function 
remain.

This is performed 
by functions in `lang/src/partial_eval.rs`.

The result is still represented
using the `Comp`/`Val` AST.

```
#[verify]
fn add_twice_monotonic() -> bool {
    let v3 = exists(|x: Nat, y: Nat| {
        let v0 = y == Nat::Z;
        if v0 {
            let v5 = gt(x, x);
            return v5
        } else {
            let v1 = add(x, y);
            let v2 = add(v1, y);
            let v5 = gt(x, v2);
            return v2
        }
    });
    let v6 = !v3;
    return v6
}
```

# 3. Negation-normal-form

Performed by `lang/src/neg_normal_form.rs`.

```
#[verify]
fn add_twice_monotonic() -> bool {
    forall(|x: Nat, y: Nat| {
        let v0 = y == Nat::Z;
        if v0 {
            let v5 = !gt(x, x);
            return v5
        } else {
            let v1 = add(x, y);
            let v2 = add(v1, y);
            let v5 = !gt(x, v2);
            return v5
        }
    });
}
```

# 4. Relational abstraction

Performed by `lang/src/expand_funs.rs`.

```
#[verify]
fn add_twice_monotonic() -> bool {
    forall(|x: Nat, y: Nat| {
        let v0 = y == Nat::Z;
        if v0 {
            let v5 = !gt(x, x);
            return v5
        } else {
            forall(|v1: Nat| implies(
                add_ra(x, y, v1),
                forall(|v2: Nat| implies(
                    add_ra(v1, y, v2),
                    {
                        let v5 = !gt(x, v2);
                        return v5
                    }
                ))
            ))
        }
    })
}
```

# 5. Conversion to SMT

Performed by `lang/src/smt/internal.rs`.

This takes the `Comp`/`Val` AST
and produces an `easy-smt` AST,
which is then converted by the `easy-smt` package
into actual SMTLIB code and fed to CVC5.