aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Wang2025-03-15 22:39:20 -0400
committerAnthony Wang2025-03-15 22:39:20 -0400
commita9d3267b86e144898c674ebe760024a12876460a (patch)
treeb80f960dbe314a880df9a81fa48b11be503e9457
parent6a53b84c19d7ebaf1430679d3880dc6ad38dd319 (diff)
Use int instead of nat for perf reasons
-rw-r--r--fenwick.dfy32
1 files changed, 16 insertions, 16 deletions
diff --git a/fenwick.dfy b/fenwick.dfy
index 4366668..41231ee 100644
--- a/fenwick.dfy
+++ b/fenwick.dfy
@@ -1,12 +1,12 @@
// Proof of some functions from fenwick.c
-// Dafny only supports bitwise ops on bitvectors, not nats
+// Dafny only supports bitwise ops on bitvectors, not ints
// But bitvectors are super gross
-// So let's implement i & -i for nats
+// So let's implement i & -i for ints
// Basically the largest power of 2 that divides i
// opaque for perf reasons since be always use lsb_* lemmas to reason about it
// https://dafny.org/latest/VerificationOptimization/VerificationOptimization#opaque-definitions
-opaque function lsb(i: nat): nat
+opaque function lsb(i: int): int
requires i > 0
ensures 0 < lsb(i) <= i
{
@@ -14,11 +14,11 @@ opaque function lsb(i: nat): nat
}
// Verify lsb(i) == i & -i
-lemma lsb_correct(i: nat)
+lemma lsb_correct(i: int)
// Literally just check every i
// Uh you can bump this up to 2^32 and bv32 but it takes forever to check
requires 0 < i < 256
- ensures lsb(i) == ((i as bv8) & -(i as bv8)) as nat
+ ensures lsb(i) == ((i as bv8) & -(i as bv8)) as int
{
// Dafny can autoprove this using aggressive inlining
reveal lsb;
@@ -28,7 +28,7 @@ lemma lsb_correct(i: nat)
// i + lsb(i) is the parent of i
// The lsb of i is less than the lsb of its parent
// Definitely the most important property of lsb
-lemma lsb_add(i: nat)
+lemma lsb_add(i: int)
requires i > 0
ensures 2 * lsb(i) <= lsb(i + lsb(i))
{
@@ -40,7 +40,7 @@ lemma lsb_add(i: nat)
// Used for correctness in update
// No intervals touch i between i and i + lsb(i)
-lemma lsb_next(i: nat)
+lemma lsb_next(i: int)
requires i > 0
ensures forall j :: i < j < i + lsb(i) ==> j - lsb(j) >= i
{
@@ -50,7 +50,7 @@ lemma lsb_next(i: nat)
// Used for correctness in constructor
// If the i and i + lsb(i) intervals start at the same place
// Then i is the first child for i + lsb(i)
-lemma lsb_no_par(i: nat, j: nat)
+lemma lsb_no_par(i: int, j: int)
requires 0 < j < i
requires i - lsb(i) == i + lsb(i) - lsb(i + lsb(i))
ensures j + lsb(j) != i + lsb(i)
@@ -62,7 +62,7 @@ lemma lsb_no_par(i: nat, j: nat)
// Used for correctness in constructor
// If the interval for i starts after the interval for i + lsb(i)
// Then i - lsb(i) also has parent i + lsb(i)
-lemma lsb_shared_par(i: nat)
+lemma lsb_shared_par(i: int)
requires i > 0
requires i - lsb(i) > i + lsb(i) - lsb(i + lsb(i))
ensures i - lsb(i) + lsb(i - lsb(i)) == i + lsb(i)
@@ -76,7 +76,7 @@ lemma lsb_shared_par(i: nat)
// Used for correctness in constructor
// If j is pretty close to its parent
// Then its parent cannot be i + lsb(i)
-lemma lsb_bad_par(i: nat, j: nat)
+lemma lsb_bad_par(i: int, j: int)
requires 0 < j < i
requires j + (lsb(j) + 1) / 2 > i
ensures j + lsb(j) != i + lsb(i)
@@ -94,7 +94,7 @@ opaque ghost function sum(s: seq<int>): int
}
// Sum behaves nicely when splitting a slice
-lemma split(A: seq<int>, i: nat, j: nat, k: nat)
+lemma split(A: seq<int>, i: int, j: int, k: int)
decreases |A| - i
requires 0 <= i <= j <= k <= |A|
ensures sum(A[i..j]) + sum(A[j..k]) == sum(A[i..k])
@@ -106,7 +106,7 @@ lemma split(A: seq<int>, i: nat, j: nat, k: nat)
}
// Similar to split, but with an element in the middle
-lemma split3(A: seq<int>, i: nat, j: nat, k: nat)
+lemma split3(A: seq<int>, i: int, j: int, k: int)
requires 0 <= i < j <= k <= |A|
ensures sum(A[i..j - 1]) + A[j - 1] + sum(A[j..k]) == sum(A[i..k])
{
@@ -118,7 +118,7 @@ lemma split3(A: seq<int>, i: nat, j: nat, k: nat)
// Alright time for the fun stuff
// Buckle up, it's gonna get super crazy
class fenwick {
- var N: nat
+ var N: int
// A is the "ground truth" array
// Spooky spooky
// It's easier to use a seq here because unlike arrays, they're immutable
@@ -226,7 +226,7 @@ class fenwick {
}
// Add v to A[i']
- method update(i': nat, v: int)
+ method update(i': int, v: int)
modifies this
modifies F
requires 0 < i' <= N
@@ -311,14 +311,14 @@ class fenwick {
}
// Query for prefix sum up to i' inclusive
- method query(i': nat) returns (ret: int)
+ method query(i': int) returns (ret: int)
requires 0 < i' <= N
requires valid()
ensures ret == sum(A[0..i'])
{
- reveal sum;
ret := 0;
var i := i';
+ assert ret == sum(A[i'..i']) by { reveal sum; }
while i > 0
decreases i
invariant i >= 0