-
Notifications
You must be signed in to change notification settings - Fork 78
/
Copy pathrecursion.rs
116 lines (104 loc) · 2.2 KB
/
recursion.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use builtin::*;
use builtin_macros::*;
#[allow(unused_imports)]
use vstd::{modes::*, prelude::*, seq::*, *};
verus! {
spec fn arith_sum_int(i: int) -> int
decreases i,
{
if i <= 0 {
0
} else {
i + arith_sum_int(i - 1)
}
}
#[verifier::opaque]
spec fn arith_sum_u64(i: u64) -> u64
decreases i,
{
if i == 0 {
0
} else {
(i + arith_sum_u64((i - 1) as u64)) as u64
}
}
proof fn arith_sum_int_nonneg(i: nat)
ensures
arith_sum_int(i as int) >= 0,
decreases i,
{
if i > 0 {
arith_sum_int_nonneg((i - 1) as nat);
}
}
proof fn arith_sum_test1() {
assert(arith_sum_int(0) == 0);
// Recursive functions default to 1 fuel, so without the assert above,
// the following assert will fail
assert(arith_sum_int(1) == 1);
assert(arith_sum_int(2) == 3);
assert(arith_sum_int(3) == 6);
}
proof fn arith_sum_test2() {
// Instead of writing out intermediate assertions,
// we can instead boost the fuel setting
reveal_with_fuel(arith_sum_int, 4);
assert(arith_sum_int(3) == 6);
}
proof fn arith_sum_test3() {
reveal_with_fuel(arith_sum_u64, 4);
assert(arith_sum_u64(3) == 6);
}
proof fn arith_sum_monotonic(i: nat, j: nat)
requires
i <= j,
ensures
arith_sum_int(i as int) <= arith_sum_int(j as int),
decreases j,
{
if i < j {
arith_sum_monotonic(i, (j - 1) as nat);
}
}
fn compute_arith_sum(n: u64) -> (sum: u64)
requires
n < 100,
ensures
arith_sum_int(n as int) == sum,
{
let mut sum: u64 = 0;
for i in 0..n
invariant
n < 100,
arith_sum_int(i as int) == sum,
sum <= 100 * i,
{
sum = sum + (i + 1);
}
sum
}
fn run_arith_sum(n: u64) -> u64 {
let mut result: u64 = 0;
if n < 100 {
result = compute_arith_sum(n);
}
result
}
fn exec_with_decreases(n: u64) -> u64
decreases 100 - n,
{
if n < 100 {
exec_with_decreases(n + 1)
} else {
n
}
}
} // verus!
fn main() {
let args = std::env::args();
for arg in args {
if let Ok(n) = arg.parse::<u64>() {
println!("{}", run_arith_sum(n));
}
}
}