.mbt + .mbtp moonc prove Why3 + Z3
┌────────────┐ ┌──────────────┐ ┌──────────────┐
│ Source code │ ───► │ Generate │ ───► │ Prove goals │
│ + predicates│ │ WhyML (.mlw) │ │ via SMT │
└────────────┘ └──────────────┘ └──────────────┘predicate in_bounds(xs : FixedArray[Int], i : Int) {
(0 <= i) && (i < xs.length())
}
predicate sorted(xs : FixedArray[Int]) {
i : Int, j : Int,
((in_bounds(xs, i)) && (in_bounds(xs, j)) && (i <= j))
xs[i] <= xs[j]
}pub fn lower_bound(xs : FixedArray[Int], key : Int) -> Int {
proof_require: sorted(xs),
proof_ensure: result => lower_bound_ok(xs, key, result),
} {
for lo = 0, hi = xs.length(); lo < hi; {
let mid = lo + (hi - lo) / 2
if xs[mid] < key {
continue mid + 1, hi
} else {
continue lo, mid
}
} {
lo
} {
proof_invariant: 0 <= lo,
proof_invariant: lo <= hi,
proof_invariant: hi <= xs.length(),
proof_invariant: all_less_before(xs, key, lo),
proof_invariant: all_geq_from(xs, key, hi),
}
}| MoonBit | WhyML |
|---|---|
| FixedArray[Int] | array int |
| xs.length() | xs.length |
| xs[i] | xs[i] |
| && / \|\| | /\ / \/ |
| ∀ x : Int, | forall x : int. |
| → | -> |
| for loop | while loop with ref variables |
| loop invariants | invariant { ... } clauses |
| proof_require / proof_ensure | requires { ... } / ensures { ... } |
Z3 @ 0.2s, 1000 MB → quick wins
Z3 @ 1s, 1000 MB → moderate goals
compute_specified → unfold definitions
split_vc → break conjunction goals apart
Z3 @ 2s, 4000 MB → harder goalsmoon prove| Package | What it proves |
|---|---|
| abs | \|x\| >= 0 and equals x or -x |
| maxfn | max(a,b) >= a, >= b, and equals one of them |
| clamp | lo <= clamp(x, lo, hi) <= hi given lo <= hi |
| Package | What it proves |
|---|---|
| find | Linear search: result is -1 or a valid index with matching key |
| count | Count non-negatives: 0 <= result <= length |
| gauss | Sum 1..n: result * 2 == n * (n + 1) (Gauss formula) |
| Package | What it proves |
|---|---|
| binary_search | Option-returning binary search with strong window invariants |
| invpred | Binary search using a named invariant predicate |
| isqrt | Integer square root via binary search: r*r <= n < (r+1)*(r+1) |
| div | Integer division via binary search: q*b <= a < (q+1)*b |
| Package | What it proves |
|---|---|
| maxarr | Index of max element: ∀ k, xs[k] <= xs[result] |
| lowerbound | Lower bound binary search: ∀ i < result, xs[i] < key and ∀ i >= result, xs[i] >= key — combines quantified invariants with sorted precondition |
| sumbounds | Array sum bounded by element range: lo*n <= sum <= hi*n — nonlinear arithmetic with quantified precondition |
| checksorted | If result == 1, all adjacent pairs in order — connects a boolean flag to a quantified property |
| arreq | Two-array equality: if result == 1, ∀ k, xs[k] == ys[k] |