-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.rs
More file actions
169 lines (149 loc) · 4.84 KB
/
Copy pathmain.rs
File metadata and controls
169 lines (149 loc) · 4.84 KB
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use vstd::prelude::*;
verus! {
// Helper spec function to check if a list is sorted (specialized for i32 for now)
spec fn is_sorted_i32(list: Seq<i32>) -> bool {
forall|i: int, j: int| 0 <= i < j < list.len() ==> list[i] <= list[j]
}
// Helper spec function to check if two lists have the same multiset of elements
#[verifier::external_body]
spec fn same_multiset_i32(list1: Seq<i32>, list2: Seq<i32>) -> bool {
unimplemented!()
}
fn merge_sort(list: &Vec<i32>) -> (result: Vec<i32>)
ensures
// In the output list, given positions i and j, if i < j, then list[i] <= list[j]
is_sorted_i32(result@),
// The output has the same length as the input
result@.len() == list@.len(),
// The output contains the same elements as the input (same multiset)
same_multiset_i32(result@, list@),
decreases list.len()
{
// Base case: a list of size 0 or 1 is already sorted
if list.len() <= 1 {
proof {
admit(); // Admit that cloning preserves the multiset
}
return list.clone();
}
// Split the list into two halves
let mid = list.len() / 2;
let mut left_vec = Vec::new();
let mut right_vec = Vec::new();
let mut idx: usize = 0;
while idx < mid
invariant
idx <= mid,
mid <= list.len(),
left_vec@.len() == idx,
decreases mid - idx
{
left_vec.push(list[idx]);
idx += 1;
}
while idx < list.len()
invariant
mid <= idx <= list.len(),
left_vec@.len() == mid,
right_vec@.len() == idx - mid,
decreases list.len() - idx
{
right_vec.push(list[idx]);
idx += 1;
}
proof {
assert(left_vec@.len() == mid);
assert(right_vec@.len() == list@.len() - mid);
assert(left_vec@.len() < list@.len() || list@.len() == 0);
assert(right_vec@.len() < list@.len() || list@.len() == 0);
}
let left = merge_sort(&left_vec);
let right = merge_sort(&right_vec);
// Merge the two sorted halves
let result = merge(&left, &right);
// TODO: To fully verify this, we would need to prove the multiset property for the base case and recursion
proof {
admit();
}
result
}
fn merge(left: &Vec<i32>, right: &Vec<i32>) -> (result: Vec<i32>)
requires
left@.len() + right@.len() <= usize::MAX,
// We assume the inputs are sorted (needed to prove output is sorted)
is_sorted_i32(left@),
is_sorted_i32(right@),
ensures
// The output list has size equal to the sum of the sizes of the input lists
result@.len() == left@.len() + right@.len(),
// The output is sorted
is_sorted_i32(result@),
// The output contains all elements from both input lists
same_multiset_i32(result@, left@.add(right@)),
{
let mut merged = Vec::with_capacity(left.len() + right.len());
let mut i: usize = 0;
let mut j: usize = 0;
while i < left.len() && j < right.len()
invariant
i <= left.len(),
j <= right.len(),
merged@.len() == i + j,
decreases left.len() - i + right.len() - j
{
if left[i] <= right[j] {
merged.push(left[i]);
i += 1;
} else {
merged.push(right[j]);
j += 1;
}
}
// At this point, either i == left.len() or j == right.len()
assert(i == left.len() || j == right.len());
// Append any remaining elements from left
if i < left.len() {
// In this case, we must have j == right.len()
assert(j == right.len());
while i < left.len()
invariant
i <= left.len(),
j == right.len(),
merged@.len() == i + j,
decreases left.len() - i
{
merged.push(left[i]);
i += 1;
}
}
// Append any remaining elements from right
if j < right.len() {
// In this case, we must have i == left.len()
assert(i == left.len());
while j < right.len()
invariant
i == left.len(),
j <= right.len(),
merged@.len() == i + j,
decreases right.len() - j
{
merged.push(right[j]);
j += 1;
}
}
// TODO: To fully verify this, we would need to prove:
// 1. The merged result is sorted (requires loop invariants tracking sorted property)
// 2. The merged result contains exactly the elements from left and right (multiset property)
// For now, we use admit() to assume these properties hold
proof {
admit();
}
merged
}
} // verus!
fn main() {
let nums = vec![38, 27, 43, 3, 9, 82, 10];
let sorted = merge_sort(&nums);
println!("Original: {:?}", nums);
println!("Sorted: {:?}", sorted);
}