1use vstd::prelude::*;
11
12verus! {
13
14#[derive(Clone, Copy, PartialEq, Eq, Debug)]
15pub enum Round {
16 Idle,
17 Running,
18}
19
20pub open spec fn has_better_in_neighbor(
21 edges: Seq<(usize, usize)>,
22 snapshot: Seq<u64>,
23 n: usize,
24) -> bool {
25 exists|i: int| 0 <= i < edges.len()
26 && edges[i].1 == n
27 && snapshot[edges[i].0 as int] < snapshot[n as int]
28}
29
30pub open spec fn local_combine(
31 edges: Seq<(usize, usize)>,
32 snapshot: Seq<u64>,
33 n: usize,
34) -> int {
35 if has_better_in_neighbor(edges, snapshot, n) {
36 snapshot[n as int] as int - 1
37 } else {
38 snapshot[n as int] as int
39 }
40}
41
42pub struct PropagationPass {
43 pub num_nodes: usize,
44 pub max_iterations: u64,
45 pub max_value: u64,
46 pub edges: Vec<(usize, usize)>,
47 pub values: Vec<u64>,
48 pub snapshot: Vec<u64>,
49 pub updated: Vec<bool>,
50 pub iteration: u64,
51 pub changed: bool,
52 pub round: Round,
53}
54
55impl PropagationPass {
56 pub open spec fn type_invariant(&self) -> bool {
59 &&& self.values.len() == self.num_nodes
60 &&& self.snapshot.len() == self.num_nodes
61 &&& self.updated.len() == self.num_nodes
62 &&& (forall|i: int| 0 <= i < self.values.len()
63 ==> #[trigger] self.values@[i] <= self.max_value)
64 &&& (forall|i: int| 0 <= i < self.snapshot.len()
65 ==> #[trigger] self.snapshot@[i] <= self.max_value)
66 &&& (forall|i: int| 0 <= i < self.edges.len()
67 ==> #[trigger] self.edges@[i].0 < self.num_nodes
68 && self.edges@[i].1 < self.num_nodes)
69 }
70
71 pub open spec fn iteration_bound(&self) -> bool {
72 self.iteration <= self.max_iterations
73 }
74
75 pub open spec fn round_bound(&self) -> bool {
76 self.round == Round::Running ==> self.iteration < self.max_iterations
77 }
78
79 pub open spec fn running_changed(&self) -> bool {
80 self.round == Round::Running ==> self.changed
81 }
82
83 pub open spec fn all_updated(&self) -> bool {
84 forall|i: int| 0 <= i < self.updated.len() ==> #[trigger] self.updated@[i]
85 }
86
87 pub open spec fn snapshot_locality(&self) -> bool {
90 forall|i: int| 0 <= i < self.updated.len() && #[trigger] self.updated@[i]
91 ==> self.values@[i] as int == local_combine(self.edges@, self.snapshot@, i as usize)
92 }
93
94 pub open spec fn settled_ok(&self) -> bool {
95 !self.changed ==> self.values@ == self.snapshot@ && self.all_updated()
96 }
97
98 pub open spec fn inv(&self) -> bool {
99 &&& self.type_invariant()
100 &&& self.iteration_bound()
101 &&& self.round_bound()
102 &&& self.running_changed()
103 &&& self.settled_ok()
104 &&& self.snapshot_locality()
105 }
106
107 pub open spec fn settled_or_iteration_limit(&self) -> bool {
108 !self.changed || self.iteration == self.max_iterations
109 }
110
111 pub fn new(
114 num_nodes: usize,
115 max_iterations: u64,
116 max_value: u64,
117 edges: Vec<(usize, usize)>,
118 init_values: Vec<u64>,
119 ) -> (p: PropagationPass)
120 requires
121 init_values.len() == num_nodes,
122 forall|i: int| 0 <= i < init_values.len() ==> init_values@[i] <= max_value,
123 forall|i: int| 0 <= i < edges.len()
124 ==> edges@[i].0 < num_nodes && edges@[i].1 < num_nodes,
125 ensures
126 p.num_nodes == num_nodes,
127 p.max_iterations == max_iterations,
128 p.max_value == max_value,
129 p.edges@ == edges@,
130 p.values@ == init_values@,
131 p.snapshot@ == init_values@,
132 p.iteration == 0,
133 p.changed,
134 p.round == Round::Idle,
135 forall|i: int| 0 <= i < p.updated.len() ==> !p.updated@[i],
136 p.inv(),
137 {
138 let snapshot = clone_values(&init_values);
139 let updated = false_vector(num_nodes);
140 PropagationPass {
141 num_nodes,
142 max_iterations,
143 max_value,
144 edges,
145 values: init_values,
146 snapshot,
147 updated,
148 iteration: 0,
149 changed: true,
150 round: Round::Idle,
151 }
152 }
153
154 pub fn all_nodes_updated(&self) -> (b: bool)
157 requires self.type_invariant(),
158 ensures b == self.all_updated(),
159 {
160 let n = self.updated.len();
161 let mut i: usize = 0;
162 while i < n
163 invariant
164 i <= n,
165 n == self.updated.len(),
166 forall|k: int| 0 <= k < i ==> self.updated@[k],
167 decreases n - i,
168 {
169 if !self.updated[i] {
170 assert(!self.all_updated());
171 return false;
172 }
173 i = i + 1;
174 }
175 assert(self.all_updated());
176 true
177 }
178
179 pub fn combine_node(&self, n: usize) -> (value: u64)
181 requires
182 self.type_invariant(),
183 n < self.num_nodes,
184 ensures
185 value as int == local_combine(self.edges@, self.snapshot@, n),
186 value <= self.max_value,
187 {
188 let edge_count = self.edges.len();
189 let mut i: usize = 0;
190 while i < edge_count
191 invariant
192 i <= edge_count,
193 edge_count == self.edges.len(),
194 self.type_invariant(),
195 n < self.num_nodes,
196 forall|j: int| 0 <= j < i ==> !(
197 self.edges@[j].1 == n
198 && self.snapshot@[self.edges@[j].0 as int] < self.snapshot@[n as int]
199 ),
200 decreases edge_count - i,
201 {
202 let edge = self.edges[i];
203 if edge.1 == n && self.snapshot[edge.0] < self.snapshot[n] {
204 assert(has_better_in_neighbor(self.edges@, self.snapshot@, n));
205 assert(self.snapshot@[n as int] > 0);
206 return self.snapshot[n] - 1;
207 }
208 i = i + 1;
209 }
210 assert(!has_better_in_neighbor(self.edges@, self.snapshot@, n));
211 self.snapshot[n]
212 }
213
214 pub fn start_round(&mut self)
218 requires
219 old(self).inv(),
220 old(self).round == Round::Idle,
221 old(self).changed,
222 old(self).iteration < old(self).max_iterations,
223 ensures
224 final(self).num_nodes == old(self).num_nodes,
225 final(self).max_iterations == old(self).max_iterations,
226 final(self).max_value == old(self).max_value,
227 final(self).edges@ == old(self).edges@,
228 final(self).values@ == old(self).values@,
229 final(self).snapshot@ == old(self).values@,
230 forall|i: int| 0 <= i < final(self).updated.len() ==> !final(self).updated@[i],
231 final(self).iteration == old(self).iteration,
232 final(self).changed == old(self).changed,
233 final(self).round == Round::Running,
234 final(self).inv(),
235 {
236 self.snapshot = clone_values(&self.values);
237 self.updated = false_vector(self.num_nodes);
238 self.round = Round::Running;
239 }
240
241 pub fn update_node(&mut self, n: usize)
243 requires
244 old(self).inv(),
245 old(self).round == Round::Running,
246 n < old(self).num_nodes,
247 !old(self).updated@[n as int],
248 ensures
249 final(self).num_nodes == old(self).num_nodes,
250 final(self).max_iterations == old(self).max_iterations,
251 final(self).max_value == old(self).max_value,
252 final(self).edges@ == old(self).edges@,
253 final(self).snapshot@ == old(self).snapshot@,
254 final(self).values@ == old(self).values@.update(
255 n as int,
256 local_combine(old(self).edges@, old(self).snapshot@, n) as u64,
257 ),
258 final(self).updated@ == old(self).updated@.update(n as int, true),
259 final(self).iteration == old(self).iteration,
260 final(self).changed == old(self).changed,
261 final(self).round == old(self).round,
262 final(self).inv(),
263 {
264 let next = self.combine_node(n);
265 self.values.set(n, next);
266 self.updated.set(n, true);
267 assert(self.snapshot_locality()) by {
268 assert forall|i: int| 0 <= i < self.updated.len() && self.updated@[i]
269 implies self.values@[i] as int
270 == local_combine(self.edges@, self.snapshot@, i as usize) by {
271 if i == n as int {
272 assert(self.values@[i] == next);
273 } else {
274 assert(self.values@[i] == old(self).values@[i]);
275 assert(self.updated@[i] == old(self).updated@[i]);
276 }
277 }
278 }
279 }
280
281 pub fn end_round(&mut self)
283 requires
284 old(self).inv(),
285 old(self).round == Round::Running,
286 old(self).all_updated(),
287 ensures
288 final(self).num_nodes == old(self).num_nodes,
289 final(self).max_iterations == old(self).max_iterations,
290 final(self).max_value == old(self).max_value,
291 final(self).edges@ == old(self).edges@,
292 final(self).values@ == old(self).values@,
293 final(self).snapshot@ == old(self).snapshot@,
294 final(self).updated@ == old(self).updated@,
295 crate::connectives::counter::increment(
296 old(self).iteration as int,
297 final(self).iteration as int,
298 ),
299 final(self).changed == (old(self).values@ != old(self).snapshot@),
300 final(self).round == Round::Idle,
301 final(self).inv(),
302 {
303 let differ = !vectors_equal(&self.values, &self.snapshot);
304 self.changed = differ;
305 self.iteration = self.iteration + 1;
306 self.round = Round::Idle;
307 }
308
309 pub fn terminate(&mut self)
311 requires
312 old(self).inv(),
313 old(self).round == Round::Idle,
314 old(self).settled_or_iteration_limit(),
315 ensures
316 final(self).num_nodes == old(self).num_nodes,
317 final(self).max_iterations == old(self).max_iterations,
318 final(self).max_value == old(self).max_value,
319 final(self).edges@ == old(self).edges@,
320 final(self).values@ == old(self).values@,
321 final(self).snapshot@ == old(self).snapshot@,
322 final(self).updated@ == old(self).updated@,
323 final(self).iteration == old(self).iteration,
324 final(self).changed == old(self).changed,
325 final(self).round == old(self).round,
326 final(self).inv(),
327 {
328 }
329}
330
331fn false_vector(n: usize) -> (out: Vec<bool>)
332 ensures
333 out.len() == n,
334 forall|i: int| 0 <= i < out.len() ==> !out@[i],
335{
336 let mut out: Vec<bool> = Vec::new();
337 let mut i: usize = 0;
338 while i < n
339 invariant
340 i <= n,
341 out.len() == i,
342 forall|k: int| 0 <= k < i ==> !out@[k],
343 decreases n - i,
344 {
345 out.push(false);
346 i = i + 1;
347 }
348 out
349}
350
351fn clone_values(v: &Vec<u64>) -> (out: Vec<u64>)
352 ensures out@ == v@,
353{
354 let mut out: Vec<u64> = Vec::new();
355 let n = v.len();
356 let mut i: usize = 0;
357 while i < n
358 invariant
359 i <= n,
360 n == v.len(),
361 out.len() == i,
362 forall|k: int| 0 <= k < i ==> out@[k] == v@[k],
363 decreases n - i,
364 {
365 out.push(v[i]);
366 i = i + 1;
367 }
368 assert(out@ =~= v@);
369 out
370}
371
372fn vectors_equal(a: &Vec<u64>, b: &Vec<u64>) -> (same: bool)
373 requires a.len() == b.len(),
374 ensures same == (a@ == b@),
375{
376 let n = a.len();
377 let mut i: usize = 0;
378 while i < n
379 invariant
380 i <= n,
381 n == a.len(),
382 a.len() == b.len(),
383 forall|k: int| 0 <= k < i ==> a@[k] == b@[k],
384 decreases n - i,
385 {
386 if a[i] != b[i] {
387 assert(a@[i as int] != b@[i as int]);
388 return false;
389 }
390 i = i + 1;
391 }
392 assert(a@ =~= b@);
393 true
394}
395
396}