automation_structures/primitives/
backtracking_traversal.rs1use vstd::prelude::*;
9
10verus! {
11
12pub struct UndoToken {
14 pub saved: u64,
16 pub delta: u64,
18}
19
20pub struct BacktrackingTraversal {
22 pub branch_factor: u64,
24 pub max_depth: usize,
26 pub init_aux: u64,
28 pub path: Vec<u64>,
30 pub aux: u64,
32 pub ledger: Vec<UndoToken>,
34 pub visited: Vec<Vec<u64>>,
37}
38
39impl BacktrackingTraversal {
40 pub open spec fn mutate_spec(v: u64, d: u64) -> int {
42 ((v as int) + (d as int)) % 3
43 }
44
45 pub open spec fn undo_spec(v: u64, d: u64) -> int {
47 ((v as int) + (3 - d as int)) % 3
48 }
49
50 pub open spec fn type_invariant(&self) -> bool {
52 &&& self.init_aux < 3
53 &&& self.aux < 3
54 &&& self.path.len() <= self.max_depth
55 &&& (forall|i: int| 0 <= i < self.path.len()
56 ==> 1 <= #[trigger] self.path@[i] <= self.branch_factor)
57 &&& (forall|i: int| 0 <= i < self.ledger.len() ==> {
58 &&& #[trigger] self.ledger@[i].saved < 3
59 &&& 1 <= self.ledger@[i].delta <= 2
60 })
61 }
62
63 pub open spec fn pairing(&self) -> bool {
66 &&& self.ledger.len() == self.path.len()
67 &&& (self.path.len() == 0 ==> self.aux == self.init_aux)
68 &&& (self.path.len() > 0 ==> self.aux as int
69 == Self::mutate_spec(
70 self.ledger@[self.path.len() - 1].saved,
71 self.ledger@[self.path.len() - 1].delta))
72 }
73
74 pub open spec fn state_restoration(&self) -> bool {
77 &&& (self.ledger.len() >= 1 ==> self.ledger@[0].saved == self.init_aux)
78 &&& (forall|i: int| 1 <= i < self.ledger.len() ==>
79 #[trigger] self.ledger@[i].saved as int
80 == Self::mutate_spec(self.ledger@[i - 1].saved, self.ledger@[i - 1].delta))
81 }
82
83 pub open spec fn completeness(&self) -> bool {
85 forall|e: int| 0 <= e < self.visited.len() ==> {
86 &&& #[trigger] self.visited@[e].len() == self.max_depth
87 &&& (forall|j: int| 0 <= j < self.max_depth as int
88 ==> 1 <= #[trigger] self.visited@[e]@[j] <= self.branch_factor)
89 }
90 }
91
92 pub open spec fn visited_unique(&self) -> bool {
94 forall|i: int, j: int|
95 0 <= i < self.visited.len() && 0 <= j < self.visited.len() && i != j
96 ==> #[trigger] self.visited@[i]@ != #[trigger] self.visited@[j]@
97 }
98
99 pub open spec fn visited_contains(&self, p: Seq<u64>) -> bool {
101 exists|e: int| 0 <= e < self.visited.len() && #[trigger] self.visited@[e]@ == p
102 }
103
104 pub open spec fn inv(&self) -> bool {
106 self.type_invariant()
107 && self.pairing()
108 && self.state_restoration()
109 && self.completeness()
110 && self.visited_unique()
111 }
112
113 pub open spec fn is_leaf(&self) -> bool {
115 self.path.len() == self.max_depth
116 }
117
118 pub fn mutate_exec(v: u64, d: u64) -> (out: u64)
120 requires v < 3, 1 <= d <= 2,
121 ensures out < 3, out as int == Self::mutate_spec(v, d),
122 {
123 if d == 1 {
124 if v == 2 { 0 } else { v + 1 }
125 } else {
126 if v == 0 { 2 } else { v - 1 }
127 }
128 }
129
130 pub fn undo_exec(v: u64, d: u64) -> (out: u64)
132 requires v < 3, 1 <= d <= 2,
133 ensures out < 3, out as int == Self::undo_spec(v, d),
134 {
135 if d == 1 {
136 if v == 0 { 2 } else { v - 1 }
137 } else {
138 if v == 2 { 0 } else { v + 1 }
139 }
140 }
141
142 pub proof fn lemma_undo_inverts(v: u64, d: u64)
144 requires v < 3, 1 <= d <= 2,
145 ensures Self::undo_spec(Self::mutate_spec(v, d) as u64, d) == v as int,
146 {
147 if v == 0 {
148 if d == 1 { assert(Self::mutate_spec(v, d) == 1); }
149 else { assert(Self::mutate_spec(v, d) == 2); }
150 } else if v == 1 {
151 if d == 1 { assert(Self::mutate_spec(v, d) == 2); }
152 else { assert(Self::mutate_spec(v, d) == 0); }
153 } else {
154 assert(v == 2);
155 if d == 1 { assert(Self::mutate_spec(v, d) == 0); }
156 else { assert(Self::mutate_spec(v, d) == 1); }
157 }
158 }
159
160 pub fn new(branch_factor: u64, max_depth: usize, init_aux: u64) -> (t: BacktrackingTraversal)
162 requires init_aux < 3,
163 ensures
164 t.branch_factor == branch_factor,
165 t.max_depth == max_depth,
166 t.init_aux == init_aux,
167 t.path@.len() == 0,
168 t.ledger@.len() == 0,
169 t.aux == init_aux,
170 t.visited@.len() == 0,
171 t.inv(),
172 {
173 BacktrackingTraversal {
174 branch_factor,
175 max_depth,
176 init_aux,
177 path: Vec::new(),
178 aux: init_aux,
179 ledger: Vec::new(),
180 visited: Vec::new(),
181 }
182 }
183
184 pub fn is_leaf_exec(&self) -> (b: bool)
186 ensures b == self.is_leaf(),
187 {
188 self.path.len() == self.max_depth
189 }
190
191 pub fn can_descend(&self, c: u64, d: u64) -> (b: bool)
193 requires self.type_invariant(),
194 ensures b == (!self.is_leaf() && 1 <= c <= self.branch_factor && 1 <= d <= 2),
195 {
196 self.path.len() < self.max_depth
197 && 1 <= c && c <= self.branch_factor
198 && 1 <= d && d <= 2
199 }
200
201 pub fn can_ascend(&self) -> (b: bool)
203 ensures b == (self.path.len() >= 1),
204 {
205 self.path.len() >= 1
206 }
207
208 pub fn has_visited(&self, p: &Vec<u64>) -> (b: bool)
210 ensures b == self.visited_contains(p@),
211 {
212 let len = self.visited.len();
213 let mut i: usize = 0;
214 while i < len
215 invariant
216 i <= len,
217 len == self.visited.len(),
218 forall|e: int| 0 <= e < i ==> #[trigger] self.visited@[e]@ != p@,
219 decreases len - i,
220 {
221 if paths_equal(&self.visited[i], p) {
222 assert(self.visited@[i as int]@ == p@);
223 return true;
224 }
225 i = i + 1;
226 }
227 false
228 }
229
230 pub fn can_visit(&self) -> (b: bool)
232 ensures b == (self.is_leaf() && !self.visited_contains(self.path@)),
233 {
234 self.is_leaf_exec() && !self.has_visited(&self.path)
235 }
236
237 pub fn descend(&mut self, c: u64, d: u64)
239 requires
240 old(self).inv(),
241 !old(self).is_leaf(),
242 1 <= c <= old(self).branch_factor,
243 1 <= d <= 2,
244 ensures
245 final(self).branch_factor == old(self).branch_factor,
246 final(self).max_depth == old(self).max_depth,
247 final(self).init_aux == old(self).init_aux,
248 final(self).path@ == old(self).path@.push(c),
249 final(self).ledger@.len() == old(self).ledger@.len() + 1,
250 final(self).ledger@[old(self).ledger@.len() as int].saved == old(self).aux,
251 final(self).ledger@[old(self).ledger@.len() as int].delta == d,
252 forall|i: int| 0 <= i < old(self).ledger@.len() ==>
253 #[trigger] final(self).ledger@[i].saved == old(self).ledger@[i].saved
254 && final(self).ledger@[i].delta == old(self).ledger@[i].delta,
255 final(self).aux as int == Self::mutate_spec(old(self).aux, d),
256 final(self).visited@ == old(self).visited@,
257 final(self).inv(),
258 {
259 let next = Self::mutate_exec(self.aux, d);
260 let token = UndoToken { saved: self.aux, delta: d };
261 self.ledger.push(token);
262 self.path.push(c);
263 self.aux = next;
264 }
265
266 pub fn visit(&mut self)
268 requires
269 old(self).inv(),
270 old(self).is_leaf(),
271 !old(self).visited_contains(old(self).path@),
272 ensures
273 final(self).branch_factor == old(self).branch_factor,
274 final(self).max_depth == old(self).max_depth,
275 final(self).init_aux == old(self).init_aux,
276 final(self).path@ == old(self).path@,
277 final(self).ledger@ == old(self).ledger@,
278 final(self).aux == old(self).aux,
279 final(self).visited@.len() == old(self).visited@.len() + 1,
280 final(self).visited@[old(self).visited@.len() as int]@ == old(self).path@,
281 forall|i: int| 0 <= i < old(self).visited@.len()
282 ==> #[trigger] final(self).visited@[i]@ == old(self).visited@[i]@,
283 final(self).inv(),
284 {
285 let copy = clone_path(&self.path);
286 self.visited.push(copy);
287 assert(self.completeness()) by {
288 assert forall|e: int| 0 <= e < self.visited.len() implies {
289 &&& #[trigger] self.visited@[e].len() == self.max_depth
290 &&& (forall|j: int| 0 <= j < self.max_depth as int
291 ==> 1 <= #[trigger] self.visited@[e]@[j] <= self.branch_factor)
292 } by {
293 if e < old(self).visited.len() {
294 } else {
295 assert(e == old(self).visited.len());
296 assert(self.visited@[e]@ == old(self).path@);
297 assert forall|j: int| 0 <= j < self.max_depth as int
298 implies 1 <= #[trigger] self.visited@[e]@[j] <= self.branch_factor by {
299 assert(self.visited@[e]@[j] == old(self).path@[j]);
300 }
301 }
302 }
303 }
304 assert(self.visited_unique()) by {
305 assert forall|i: int, j: int|
306 0 <= i < self.visited.len() && 0 <= j < self.visited.len() && i != j
307 implies #[trigger] self.visited@[i]@ != #[trigger] self.visited@[j]@ by {
308 if i < old(self).visited.len() && j < old(self).visited.len() {
309 } else if i == old(self).visited.len() {
310 assert(self.visited@[i]@ == old(self).path@);
311 assert(self.visited@[j]@ == old(self).visited@[j]@);
312 } else {
313 assert(j == old(self).visited.len());
314 assert(self.visited@[j]@ == old(self).path@);
315 assert(self.visited@[i]@ == old(self).visited@[i]@);
316 }
317 }
318 }
319 }
320
321 pub fn ascend(&mut self)
323 requires old(self).inv(), old(self).path.len() >= 1,
324 ensures
325 final(self).branch_factor == old(self).branch_factor,
326 final(self).max_depth == old(self).max_depth,
327 final(self).init_aux == old(self).init_aux,
328 final(self).path@ == old(self).path@.drop_last(),
329 final(self).ledger@ == old(self).ledger@.drop_last(),
330 final(self).aux as int == Self::undo_spec(
331 old(self).aux,
332 old(self).ledger@[old(self).ledger@.len() - 1].delta),
333 final(self).aux == old(self).ledger@[old(self).ledger@.len() - 1].saved,
334 final(self).visited@ == old(self).visited@,
335 final(self).inv(),
336 {
337 let depth = self.path.len();
338 let saved = self.ledger[depth - 1].saved;
339 let _ = saved;
340 let delta = self.ledger[depth - 1].delta;
341 assert(self.aux as int == Self::mutate_spec(saved, delta));
342 proof { Self::lemma_undo_inverts(saved, delta); }
343 let restored = Self::undo_exec(self.aux, delta);
344 assert(restored == saved);
345 self.aux = restored;
346 self.ledger.pop();
347 self.path.pop();
348 proof {
349 assert(self.ledger@ == old(self).ledger@.drop_last());
350 assert(self.path@ == old(self).path@.drop_last());
351 assert(self.type_invariant()) by {
352 assert forall|i: int| 0 <= i < self.path.len()
353 implies 1 <= #[trigger] self.path@[i] <= self.branch_factor by {
354 assert(self.path@[i] == old(self).path@[i]);
355 }
356 assert forall|i: int| 0 <= i < self.ledger.len() implies {
357 &&& #[trigger] self.ledger@[i].saved < 3
358 &&& 1 <= self.ledger@[i].delta <= 2
359 } by {
360 assert(self.ledger@[i].saved == old(self).ledger@[i].saved);
361 assert(self.ledger@[i].delta == old(self).ledger@[i].delta);
362 }
363 }
364 assert(self.state_restoration()) by {
365 assert forall|i: int| 1 <= i < self.ledger.len() implies
366 #[trigger] self.ledger@[i].saved as int
367 == Self::mutate_spec(self.ledger@[i - 1].saved, self.ledger@[i - 1].delta) by {
368 assert(self.ledger@[i].saved == old(self).ledger@[i].saved);
369 assert(self.ledger@[i - 1].saved == old(self).ledger@[i - 1].saved);
370 assert(self.ledger@[i - 1].delta == old(self).ledger@[i - 1].delta);
371 }
372 }
373 assert(self.pairing()) by {
374 if self.path.len() == 0 {
375 assert(depth == 1);
376 assert(old(self).ledger@[0].saved == self.init_aux);
377 } else {
378 assert(depth >= 2);
379 assert(old(self).ledger@[depth - 1].saved as int
380 == Self::mutate_spec(
381 old(self).ledger@[depth - 2].saved,
382 old(self).ledger@[depth - 2].delta));
383 }
384 }
385 }
386 }
387}
388
389fn paths_equal(a: &Vec<u64>, b: &Vec<u64>) -> (same: bool)
390 ensures same == (a@ == b@),
391{
392 if a.len() != b.len() {
393 return false;
394 }
395 let len = a.len();
396 let mut i: usize = 0;
397 while i < len
398 invariant
399 i <= len,
400 len == a.len(),
401 len == b.len(),
402 forall|k: int| 0 <= k < i ==> #[trigger] a@[k] == b@[k],
403 decreases len - i,
404 {
405 if a[i] != b[i] {
406 return false;
407 }
408 i = i + 1;
409 }
410 assert(a@ =~= b@);
411 true
412}
413
414fn clone_path(p: &Vec<u64>) -> (out: Vec<u64>)
415 ensures out@ == p@,
416{
417 let mut out: Vec<u64> = Vec::new();
418 let n = p.len();
419 let mut i: usize = 0;
420 while i < n
421 invariant
422 i <= n,
423 n == p.len(),
424 out.len() == i,
425 forall|k: int| 0 <= k < i ==> out@[k] == p@[k],
426 decreases n - i,
427 {
428 out.push(p[i]);
429 i = i + 1;
430 }
431 assert(out@ =~= p@);
432 out
433}
434
435}