1#[allow(unused_imports)]
8use vstd::prelude::*;
9
10verus! {
11
12pub open spec fn sorted(k: Seq<(u32, u32)>) -> bool {
14 forall|i: int, j: int| 0 <= i < j < k.len() ==> (#[trigger] k[i]).0 < (#[trigger] k[j]).0
15}
16
17pub open spec fn kept(keep: Seq<u32>) -> spec_fn((u32, u32)) -> bool {
19 |p: (u32, u32)| keep.contains(p.0)
20}
21
22pub open spec fn has_cat(k: Seq<(u32, u32)>, c: u32) -> bool {
24 exists|i: int| 0 <= i < k.len() && (#[trigger] k[i]).0 == c
25}
26
27pub open spec fn agree(a: Seq<(u32, u32)>, b: Seq<(u32, u32)>) -> bool {
29 forall|i: int, j: int|
30 0 <= i < a.len() && 0 <= j < b.len() && (#[trigger] a[i]).0 == (#[trigger] b[j]).0 ==> a[i]
31 == b[j]
32}
33
34proof fn lemma_push_contains(r0: Seq<(u32, u32)>, x: (u32, u32))
36 ensures
37 r0.push(x).contains(x),
38 forall|y: (u32, u32)| r0.contains(y) ==> #[trigger] r0.push(x).contains(y),
39{
40 assert(r0.push(x)[r0.len() as int] == x);
41 assert forall|y: (u32, u32)| r0.contains(y) implies #[trigger] r0.push(x).contains(y) by {
42 let t = choose|t: int| 0 <= t < r0.len() && r0[t] == y;
43 assert(r0.push(x)[t] == y);
44 }
45}
46
47#[inline]
49fn has(keep: &[u32], c: u32) -> (b: bool)
50 ensures
51 b == keep@.contains(c),
52{
53 let mut i = 0;
54 while i < keep.len()
55 invariant
56 0 <= i <= keep.len(),
57 forall|m: int| 0 <= m < i ==> keep@[m] != c,
58 decreases keep.len() - i,
59 {
60 if keep[i] == c {
61 assert(keep@[i as int] == c);
62 return true;
63 }
64 i += 1;
65 }
66 false
67}
68
69#[inline]
73pub fn project(k: &[(u32, u32)], keep: &[u32]) -> (r: Vec<(u32, u32)>)
74 ensures
75 r@ == k@.filter(kept(keep@)),
76 sorted(k@) ==> sorted(r@),
77{
78 let mut r: Vec<(u32, u32)> = Vec::with_capacity(k.len());
79 let mut i = 0;
80 while i < k.len()
81 invariant
82 0 <= i <= k.len(),
83 r@ == k@.subrange(0, i as int).filter(kept(keep@)),
84 sorted(k@) ==> sorted(r@),
85 sorted(k@) ==> forall|t: int, m: int|
86 0 <= t < r.len() && i <= m < k.len() ==> (#[trigger] r@[t]).0 < (#[trigger] k@[m]).0,
87 decreases k.len() - i,
88 {
89 let x = k[i];
90 let keep_it = has(keep, x.0);
91 proof {
92 assert(k@.subrange(0, i + 1) =~= k@.subrange(0, i as int).push(x));
93 k@.subrange(0, i as int).lemma_filter_push(x, kept(keep@));
94 }
95 if keep_it {
96 r.push(x);
97 }
98 i += 1;
99 }
100 assert(k@.subrange(0, k.len() as int) =~= k@);
101 r
102}
103
104#[inline]
109pub fn union_keys(a: &[(u32, u32)], b: &[(u32, u32)]) -> (r: Vec<(u32, u32)>)
110 requires
111 sorted(a@),
112 sorted(b@),
113 ensures
114 sorted(r@),
115 forall|x: (u32, u32)| a@.contains(x) ==> r@.contains(x),
116 forall|x: (u32, u32)| #[trigger] b@.contains(x) ==> r@.contains(x) || has_cat(a@, x.0),
117 agree(a@, b@) ==> forall|x: (u32, u32)| b@.contains(x) ==> r@.contains(x),
118 forall|x: (u32, u32)| r@.contains(x) ==> a@.contains(x) || b@.contains(x),
119{
120 broadcast use vstd::seq_lib::lemma_seq_contains_after_push;
121
122 let mut r: Vec<(u32, u32)> = Vec::with_capacity(a.len().saturating_add(b.len()));
123 let mut i = 0;
124 let mut j = 0;
125 while i < a.len() || j < b.len()
126 invariant
127 0 <= i <= a.len(),
128 0 <= j <= b.len(),
129 sorted(a@),
130 sorted(b@),
131 sorted(r@),
132 forall|t: int, m: int|
133 0 <= t < r.len() && i <= m < a.len() ==> (#[trigger] r@[t]).0 < (#[trigger] a@[m]).0,
134 forall|t: int, m: int|
135 0 <= t < r.len() && j <= m < b.len() ==> (#[trigger] r@[t]).0 < (#[trigger] b@[m]).0,
136 forall|m: int| 0 <= m < i ==> r@.contains(#[trigger] a@[m]),
137 forall|m: int| 0 <= m < j ==> r@.contains(#[trigger] b@[m]) || has_cat(a@, b@[m].0),
138 forall|x: (u32, u32)| r@.contains(x) ==> a@.contains(x) || b@.contains(x),
139 decreases a.len() - i + b.len() - j,
140 {
141 if j >= b.len() || (i < a.len() && a[i].0 < b[j].0) {
142 let x = a[i];
143 assert(a@.contains(x) && x == a@[i as int]);
144 let ghost r0 = r@;
145 r.push(x);
146 proof {
147 lemma_push_contains(r0, x);
148 }
149 i += 1;
150 } else if i >= a.len() || b[j].0 < a[i].0 {
151 let x = b[j];
152 assert(b@.contains(x) && x == b@[j as int]);
153 let ghost r0 = r@;
154 r.push(x);
155 proof {
156 lemma_push_contains(r0, x);
157 }
158 j += 1;
159 } else {
160 let x = a[i];
161 assert(a@.contains(x) && x == a@[i as int]);
162 assert(has_cat(a@, b@[j as int].0));
163 let ghost r0 = r@;
164 r.push(x);
165 proof {
166 lemma_push_contains(r0, x);
167 }
168 i += 1;
169 j += 1;
170 }
171 }
172 proof {
173 assert forall|x: (u32, u32)| a@.contains(x) implies r@.contains(x) by {
174 let m = choose|m: int| 0 <= m < a.len() && a@[m] == x;
175 assert(r@.contains(a@[m]));
176 }
177 assert forall|x: (u32, u32)| #[trigger] b@.contains(x) implies r@.contains(x) || has_cat(
178 a@,
179 x.0,
180 ) by {
181 let m = choose|m: int| 0 <= m < b.len() && b@[m] == x;
182 assert(r@.contains(b@[m]) || has_cat(a@, b@[m].0));
183 }
184 if agree(a@, b@) {
185 assert forall|x: (u32, u32)| b@.contains(x) implies r@.contains(x) by {
186 let m = choose|m: int| 0 <= m < b.len() && b@[m] == x;
187 if !r@.contains(b@[m]) {
188 let t = choose|t: int| 0 <= t < a.len() && (#[trigger] a@[t]).0 == b@[m].0;
189 assert(a@[t] == b@[m]);
190 assert(r@.contains(a@[t]));
191 }
192 }
193 }
194 }
195 r
196}
197
198} #[cfg(test)]
201#[cfg_attr(coverage_nightly, coverage(off))]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn project_filters_in_order() {
207 let k = [(1, 10), (2, 20), (3, 30)];
208 assert_eq!(project(&k, &[3, 1]), vec![(1, 10), (3, 30)]);
209 assert_eq!(project(&k, &[]), vec![]);
210 assert_eq!(project(&k, &[9]), vec![]);
211 }
212
213 #[test]
214 fn union_merges_and_left_wins() {
215 let a = [(1, 10), (3, 30)];
216 let b = [(2, 20), (3, 31), (4, 40)];
217 assert_eq!(union_keys(&a, &b), vec![(1, 10), (2, 20), (3, 30), (4, 40)]);
218 assert_eq!(union_keys(&[], &b), b.to_vec());
219 assert_eq!(union_keys(&a, &[]), a.to_vec());
220 }
221}