Skip to main content

vstd_extra/temporal_logic/
rules.rs

1// Copyright 2022 VMware, Inc.
2// SPDX-License-Identifier: MIT
3#![allow(unused_imports)]
4use super::defs::*;
5use vstd::map_lib::*;
6use vstd::prelude::*;
7
8// Internal lemmas about executions and temporal predicates.
9verus! {
10
11broadcast proof fn lemma_execution_suffix_0<T>(ex: Execution<T>)
12    ensures
13        #[trigger] ex.suffix(0) == ex,
14{
15}
16
17broadcast proof fn lemma_execution_suffix_suffix<T>(ex: Execution<T>, i: nat, j: nat)
18    ensures
19        #[trigger] ex.suffix(i).suffix(j) == ex.suffix(i + j),
20{
21}
22
23broadcast group group_execution_suffix_lemmas {
24    lemma_execution_suffix_0,
25    lemma_execution_suffix_suffix,
26}
27
28} // verus!
29verus! {
30
31broadcast proof fn implies_apply<T>(ex: Execution<T>, p: TempPred<T>, q: TempPred<T>)
32    requires
33        #[trigger] p.implies(q).satisfied_by(ex),
34        p.satisfied_by(ex),
35    ensures
36        q.satisfied_by(ex),
37{
38}
39
40proof fn implies_contraposition_apply<T>(ex: Execution<T>, p: TempPred<T>, q: TempPred<T>)
41    requires
42        p.implies(q).satisfied_by(ex),
43        not(q).satisfied_by(ex),
44    ensures
45        not(p).satisfied_by(ex),
46{
47}
48
49pub proof fn temp_pred_equality<T>(p: TempPred<T>, q: TempPred<T>)
50    requires
51        p.entails(q),
52        q.entails(p),
53    ensures
54        p == q,
55{
56    assert forall|ex: Execution<T>| #[trigger] (p.pred)(ex) == (q.pred)(ex) by {
57        if (p.pred)(ex) {
58            implies_apply::<T>(ex, p, q);
59        } else {
60            implies_contraposition_apply::<T>(ex, q, p);
61        }
62    };
63}
64
65proof fn later_unfold<T>(ex: Execution<T>, p: TempPred<T>)
66    requires
67        later(p).satisfied_by(ex),
68    ensures
69        p.satisfied_by(ex.suffix(1)),
70{
71}
72
73broadcast proof fn always_unfold<T>(ex: Execution<T>, p: TempPred<T>)
74    requires
75        #[trigger] always(p).satisfied_by(ex),
76    ensures
77        forall|i: nat| p.satisfied_by(#[trigger] ex.suffix(i)),
78{
79}
80
81proof fn eventually_unfold<T>(ex: Execution<T>, p: TempPred<T>)
82    requires
83        eventually(p).satisfied_by(ex),
84    ensures
85        exists|i: nat| p.satisfied_by(#[trigger] ex.suffix(i)),
86{
87}
88
89proof fn not_eventually_unfold<T>(ex: Execution<T>, p: TempPred<T>)
90    requires
91        not(eventually(p)).satisfied_by(ex),
92    ensures
93        forall|i| !p.satisfied_by(#[trigger] ex.suffix(i)),
94{
95}
96
97proof fn stable_unfold<T>(ex: Execution<T>, p: TempPred<T>)
98    requires
99        stable(p).satisfied_by(ex),
100    ensures
101        p.satisfied_by(ex) ==> forall|i| p.satisfied_by(#[trigger] ex.suffix(i)),
102{
103}
104
105proof fn leads_to_unfold<T>(ex: Execution<T>, p: TempPred<T>, q: TempPred<T>)
106    requires
107        p.leads_to(q).satisfied_by(ex),
108    ensures
109        forall|i: nat| p.implies(eventually(q)).satisfied_by(#[trigger] ex.suffix(i)),
110{
111}
112
113proof fn weak_fairness_unfold<T>(ex: Execution<T>, p: ActionPred<T>)
114    requires
115        weak_fairness(p).satisfied_by(ex),
116    ensures
117        forall|i|
118            always(lift_state(enabled(p))).implies(eventually(lift_action(p))).satisfied_by(
119                #[trigger] ex.suffix(i),
120            ),
121{
122}
123
124proof fn always_lift_state_unfold<T>(ex: Execution<T>, p: StatePred<T>)
125    requires
126        always(lift_state(p)).satisfied_by(ex),
127    ensures
128        forall|i| p.apply(#[trigger] ex.suffix(i).head()),
129{
130    broadcast use always_unfold;
131
132}
133
134proof fn always_lift_action_unfold<T>(ex: Execution<T>, p: ActionPred<T>)
135    requires
136        always(lift_action(p)).satisfied_by(ex),
137    ensures
138        forall|i| p.apply(#[trigger] ex.suffix(i).head(), ex.suffix(i).head_next()),
139{
140    broadcast use always_unfold;
141
142}
143
144broadcast proof fn tla_forall_unfold<T, A>(
145    ex: Execution<T>,
146    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
147)
148    requires
149        #[trigger] tla_forall(a_to_temp_pred).satisfied_by(ex),
150    ensures
151        forall|a| #[trigger] a_to_temp_pred(a).satisfied_by(ex),
152{
153}
154
155broadcast proof fn tla_exists_unfold<T, A>(
156    ex: Execution<T>,
157    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
158)
159    requires
160        #[trigger] tla_exists(a_to_temp_pred).satisfied_by(ex),
161    ensures
162        exists|a| #[trigger] a_to_temp_pred(a).satisfied_by(ex),
163{
164}
165
166proof fn tla_exists_proved_by_witness<T, A>(
167    ex: Execution<T>,
168    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
169    witness_a: A,
170)
171    requires
172        a_to_temp_pred(witness_a).satisfied_by(ex),
173    ensures
174        tla_exists(a_to_temp_pred).satisfied_by(ex),
175{
176}
177
178spec fn tla_exists_choose_witness<T, A>(
179    ex: Execution<T>,
180    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
181) -> A
182    recommends
183        exists|a| #[trigger] a_to_temp_pred(a).satisfied_by(ex),
184{
185    let witness = choose|a| #[trigger] a_to_temp_pred(a).satisfied_by(ex);
186    witness
187}
188
189proof fn implies_apply_with_always<T>(ex: Execution<T>, p: TempPred<T>, q: TempPred<T>)
190    requires
191        always(p.implies(q)).satisfied_by(ex),
192        always(p).satisfied_by(ex),
193    ensures
194        always(q).satisfied_by(ex),
195{
196    broadcast use always_unfold;
197
198}
199
200proof fn entails_apply<T>(ex: Execution<T>, p: TempPred<T>, q: TempPred<T>)
201    requires
202        p.entails(q),
203        p.satisfied_by(ex),
204    ensures
205        q.satisfied_by(ex),
206{
207    implies_apply::<T>(ex, p, q);
208}
209
210proof fn not_proved_by_contraposition<T>(ex: Execution<T>, p: TempPred<T>, q: TempPred<T>)
211    requires
212        p.implies(q).satisfied_by(ex),
213        not(q).satisfied_by(ex),
214    ensures
215        not(p).satisfied_by(ex),
216{
217}
218
219proof fn not_eventually_by_always_not<T>(ex: Execution<T>, p: TempPred<T>)
220    requires
221        always(not(p)).satisfied_by(ex),
222    ensures
223        not(eventually(p)).satisfied_by(ex),
224{
225    broadcast use always_unfold;
226
227}
228
229broadcast proof fn always_propagate_forwards<T>(ex: Execution<T>, p: TempPred<T>, i: nat)
230    requires
231        always(p).satisfied_by(ex),
232    ensures
233        #[trigger] always(p).satisfied_by(ex.suffix(i)),
234{
235    broadcast use {always_unfold, group_execution_suffix_lemmas};
236
237}
238
239proof fn always_double<T>(ex: Execution<T>, p: TempPred<T>)
240    requires
241        always(p).satisfied_by(ex),
242    ensures
243        always(always(p)).satisfied_by(ex),
244{
245    broadcast use {always_unfold, always_propagate_forwards};
246
247}
248
249proof fn always_to_current<T>(ex: Execution<T>, p: TempPred<T>)
250    requires
251        always(p).satisfied_by(ex),
252    ensures
253        p.satisfied_by(ex),
254{
255    assert(ex == ex.suffix(0));
256}
257
258proof fn always_to_future<T>(ex: Execution<T>, p: TempPred<T>, i: nat)
259    requires
260        always(p).satisfied_by(ex),
261    ensures
262        p.satisfied_by(ex.suffix(i)),
263{
264    broadcast use {always_unfold, always_propagate_forwards};
265
266}
267
268proof fn eventually_propagate_backwards<T>(ex: Execution<T>, p: TempPred<T>, i: nat)
269    requires
270        eventually(p).satisfied_by(ex.suffix(i)),
271    ensures
272        eventually(p).satisfied_by(ex),
273{
274    broadcast use group_execution_suffix_lemmas;
275
276}
277
278proof fn eventually_proved_by_witness<T>(ex: Execution<T>, p: TempPred<T>, witness_idx: nat)
279    requires
280        p.satisfied_by(ex.suffix(witness_idx)),
281    ensures
282        eventually(p).satisfied_by(ex),
283{
284}
285
286spec fn eventually_choose_witness<T>(ex: Execution<T>, p: TempPred<T>) -> nat
287    recommends
288        exists|i| p.satisfied_by(#[trigger] ex.suffix(i)),
289{
290    let witness = choose|i| p.satisfied_by(#[trigger] ex.suffix(i));
291    witness
292}
293
294proof fn valid_p_implies_always_p<T>(p: TempPred<T>)
295    requires
296        valid(p),
297    ensures
298        valid(always(p)),
299{
300}
301
302proof fn always_distributed_by_and<T>(p: TempPred<T>, q: TempPred<T>)
303    ensures
304        valid(always(p.and(q)).implies(always(p).and(always(q)))),
305{
306    broadcast use always_unfold;
307
308}
309
310proof fn p_and_always_p_equals_always_p<T>(p: TempPred<T>)
311    ensures
312        p.and(always(p)) == always(p),
313{
314    assert forall|ex| #[trigger] always(p).satisfied_by(ex) implies p.and(always(p)).satisfied_by(
315        ex,
316    ) by {
317        always_to_current::<T>(ex, p);
318    };
319    temp_pred_equality::<T>(p.and(always(p)), always(p));
320}
321
322proof fn a_to_temp_pred_equality<T, A>(p: spec_fn(A) -> TempPred<T>, q: spec_fn(A) -> TempPred<T>)
323    requires
324        forall|a: A| #[trigger] p(a).entails(q(a)) && q(a).entails(p(a)),
325    ensures
326        p == q,
327{
328    assert forall|a: A| #[trigger] p(a) == q(a) by {
329        temp_pred_equality::<T>(p(a), q(a));
330    };
331}
332
333proof fn tla_forall_or_equality<T, A>(a_to_temp_pred: spec_fn(A) -> TempPred<T>, q: TempPred<T>)
334    ensures
335        tla_forall(|a: A| a_to_temp_pred(a).or(q)) == tla_forall(a_to_temp_pred).or(q),
336{
337    broadcast use tla_forall_unfold;
338
339    let a_to_temp_pred_or_q = |a: A| a_to_temp_pred(a).or(q);
340    assert forall|ex| #[trigger] tla_forall(a_to_temp_pred_or_q).satisfied_by(ex) implies (
341    tla_forall(a_to_temp_pred).or(q)).satisfied_by(ex) by {
342        if !q.satisfied_by(ex) {
343            assert forall|a| #[trigger] a_to_temp_pred(a).satisfied_by(ex) by {
344                assert(a_to_temp_pred_or_q(a).satisfied_by(ex));
345            };
346        }
347    };
348    temp_pred_equality::<T>(
349        tla_forall(|a: A| a_to_temp_pred(a).or(q)),
350        tla_forall(a_to_temp_pred).or(q),
351    );
352}
353
354proof fn tla_exists_and_equality<T, A>(a_to_temp_pred: spec_fn(A) -> TempPred<T>, q: TempPred<T>)
355    ensures
356        tla_exists(|a: A| a_to_temp_pred(a).and(q)) == tla_exists(a_to_temp_pred).and(q),
357{
358    let a_to_temp_pred_and_q = |a: A| a_to_temp_pred(a).and(q);
359    assert forall|ex| #[trigger]
360        (tla_exists(a_to_temp_pred).and(q)).satisfied_by(ex) implies tla_exists(
361        a_to_temp_pred_and_q,
362    ).satisfied_by(ex) by {
363        let witness_a = tla_exists_choose_witness::<T, A>(ex, a_to_temp_pred);
364        tla_exists_proved_by_witness::<T, A>(ex, a_to_temp_pred_and_q, witness_a);
365    };
366    temp_pred_equality::<T>(
367        tla_exists(|a: A| a_to_temp_pred(a).and(q)),
368        tla_exists(a_to_temp_pred).and(q),
369    );
370}
371
372proof fn tla_exists_or_equality<T, A>(a_to_temp_pred: spec_fn(A) -> TempPred<T>, q: TempPred<T>)
373    ensures
374        tla_exists(|a: A| a_to_temp_pred(a).or(q)) == tla_exists(a_to_temp_pred).or(q),
375{
376    let a_to_temp_pred_or_q = |a: A| a_to_temp_pred(a).or(q);
377    assert forall|ex| #[trigger]
378        (tla_exists(a_to_temp_pred).or(q)).satisfied_by(ex) implies tla_exists(
379        a_to_temp_pred_or_q,
380    ).satisfied_by(ex) by {
381        if !q.satisfied_by(ex) {
382            let witness_a = tla_exists_choose_witness::<T, A>(ex, a_to_temp_pred);
383            tla_exists_proved_by_witness::<T, A>(ex, a_to_temp_pred_or_q, witness_a);
384        } else {
385            assert(a_to_temp_pred_or_q(arbitrary()).satisfied_by(ex));
386        }
387    };
388    temp_pred_equality::<T>(
389        tla_exists(|a: A| a_to_temp_pred(a).or(q)),
390        tla_exists(a_to_temp_pred).or(q),
391    );
392}
393
394proof fn tla_forall_implies_equality1<T, A>(
395    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
396    q: TempPred<T>,
397)
398    ensures
399        tla_forall(|a: A| a_to_temp_pred(a).implies(q)) == tla_exists(a_to_temp_pred).implies(q),
400{
401    let a_to_not_p = |a: A| not(a_to_temp_pred(a));
402    a_to_temp_pred_equality::<T, A>(
403        |a: A| a_to_temp_pred(a).implies(q),
404        |a: A| a_to_not_p(a).or(q),
405    );
406    temp_pred_equality::<T>(
407        tla_forall(|a: A| a_to_temp_pred(a).implies(q)),
408        tla_forall(|a: A| a_to_not_p(a).or(q)),
409    );
410    tla_forall_or_equality::<T, A>(a_to_not_p, q);
411    tla_forall_not_equality::<T, A>(a_to_temp_pred);
412    temp_pred_equality::<T>(
413        not(tla_exists(a_to_temp_pred)).or(q),
414        tla_exists(a_to_temp_pred).implies(q),
415    );
416}
417
418proof fn tla_forall_implies_equality2<T, A>(
419    p: TempPred<T>,
420    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
421)
422    ensures
423        tla_forall(|a: A| p.implies(a_to_temp_pred(a))) == p.implies(tla_forall(a_to_temp_pred)),
424{
425    a_to_temp_pred_equality::<T, A>(
426        |a: A| p.implies(a_to_temp_pred(a)),
427        |a: A| a_to_temp_pred(a).or(not(p)),
428    );
429    temp_pred_equality::<T>(
430        tla_forall(|a: A| p.implies(a_to_temp_pred(a))),
431        tla_forall(|a: A| a_to_temp_pred(a).or(not(p))),
432    );
433    tla_forall_or_equality::<T, A>(a_to_temp_pred, not(p));
434    temp_pred_equality::<T>(
435        tla_forall(a_to_temp_pred).or(not(p)),
436        p.implies(tla_forall(a_to_temp_pred)),
437    );
438}
439
440proof fn tla_exists_implies_equality1<T, A>(
441    p: TempPred<T>,
442    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
443)
444    ensures
445        tla_exists(|a: A| p.implies(a_to_temp_pred(a))) == p.implies(tla_exists(a_to_temp_pred)),
446{
447    a_to_temp_pred_equality::<T, A>(
448        |a: A| p.implies(a_to_temp_pred(a)),
449        |a: A| a_to_temp_pred(a).or(not(p)),
450    );
451    temp_pred_equality::<T>(
452        tla_exists(|a: A| p.implies(a_to_temp_pred(a))),
453        tla_exists(|a: A| a_to_temp_pred(a).or(not(p))),
454    );
455    tla_exists_or_equality::<T, A>(a_to_temp_pred, not(p));
456    temp_pred_equality::<T>(
457        tla_exists(a_to_temp_pred).or(not(p)),
458        p.implies(tla_exists(a_to_temp_pred)),
459    );
460}
461
462proof fn tla_forall_leads_to_equality1<T, A>(
463    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
464    q: TempPred<T>,
465)
466    ensures
467        tla_forall(|a: A| a_to_temp_pred(a).leads_to(q)) == tla_exists(a_to_temp_pred).leads_to(q),
468{
469    tla_forall_always_equality_variant::<T, A>(
470        |a: A| a_to_temp_pred(a).leads_to(q),
471        |a: A| a_to_temp_pred(a).implies(eventually(q)),
472    );
473    tla_forall_implies_equality1::<T, A>(a_to_temp_pred, eventually(q));
474}
475
476proof fn tla_forall_always_implies_equality2<T, A>(
477    p: TempPred<T>,
478    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
479)
480    ensures
481        tla_forall(|a: A| always(p.implies(a_to_temp_pred(a)))) == always(
482            p.implies(tla_forall(a_to_temp_pred)),
483        ),
484{
485    tla_forall_always_equality_variant::<T, A>(
486        |a: A| always(p.implies(a_to_temp_pred(a))),
487        |a: A| p.implies(a_to_temp_pred(a)),
488    );
489    tla_forall_implies_equality2::<T, A>(p, a_to_temp_pred);
490}
491
492proof fn tla_forall_not_equality<T, A>(a_to_temp_pred: spec_fn(A) -> TempPred<T>)
493    ensures
494        tla_forall(|a: A| not(a_to_temp_pred(a))) == not(tla_exists(a_to_temp_pred)),
495{
496    let a_to_not_p = |a: A| not(a_to_temp_pred(a));
497    assert forall|ex| #[trigger] tla_forall(a_to_not_p).satisfied_by(ex) implies not(
498        tla_exists(a_to_temp_pred),
499    ).satisfied_by(ex) by {
500        assert forall|a| !#[trigger] a_to_temp_pred(a).satisfied_by(ex) by {
501            assert(a_to_not_p(a).satisfied_by(ex));
502        };
503    };
504    temp_pred_equality::<T>(
505        tla_forall(|a: A| not(a_to_temp_pred(a))),
506        not(tla_exists(a_to_temp_pred)),
507    );
508}
509
510proof fn tla_forall_and_equality<T, A>(a_to_temp_pred: spec_fn(A) -> TempPred<T>, q: TempPred<T>)
511    ensures
512        tla_forall(|a: A| a_to_temp_pred(a).and(q)) == tla_forall(a_to_temp_pred).and(q),
513{
514    broadcast use tla_forall_unfold;
515
516    let a_to_temp_pred_and_q = |a: A| a_to_temp_pred(a).and(q);
517    assert forall|ex| #[trigger] tla_forall(a_to_temp_pred_and_q).satisfied_by(ex) implies (
518    tla_forall(a_to_temp_pred).and(q)).satisfied_by(ex) by {
519        assert forall|a| #[trigger] a_to_temp_pred(a).satisfied_by(ex) by {
520            assert(a_to_temp_pred_and_q(a).satisfied_by(ex));
521        };
522        assert(a_to_temp_pred_and_q(arbitrary()).satisfied_by(ex));
523    };
524    temp_pred_equality::<T>(
525        tla_forall(|a: A| a_to_temp_pred(a).and(q)),
526        tla_forall(a_to_temp_pred).and(q),
527    );
528}
529
530proof fn init_invariant_rec<T>(
531    ex: Execution<T>,
532    init: StatePred<T>,
533    next: ActionPred<T>,
534    inv: StatePred<T>,
535    i: nat,
536)
537    requires
538        lift_state(init).satisfied_by(ex),
539        always(lift_action(next)).satisfied_by(ex),
540        lift_state(init).implies(lift_state(inv)).satisfied_by(ex),
541        forall|idx: nat|
542            inv.apply(#[trigger] ex.suffix(idx).head()) && next.apply(
543                ex.suffix(idx).head(),
544                ex.suffix(idx).head_next(),
545            ) ==> inv.apply(ex.suffix(idx).head_next()),
546    ensures
547        inv.apply(ex.suffix(i).head()),
548    decreases i,
549{
550    broadcast use {always_unfold, group_execution_suffix_lemmas};
551
552    if i != 0 {
553        init_invariant_rec::<T>(ex, init, next, inv, (i - 1) as nat);
554    }
555}
556
557proof fn implies_new_invariant_rec<T>(
558    ex: Execution<T>,
559    init: StatePred<T>,
560    next: ActionPred<T>,
561    inv: StatePred<T>,
562    proved_inv: StatePred<T>,
563    i: nat,
564)
565    requires
566        lift_state(init).satisfied_by(ex),
567        always(lift_action(next)).satisfied_by(ex),
568        always(lift_state(proved_inv)).satisfied_by(ex),
569        lift_state(init).implies(lift_state(inv)).satisfied_by(ex),
570        forall|idx: nat|
571            inv.apply(#[trigger] ex.suffix(idx).head()) && proved_inv.apply(
572                #[trigger] ex.suffix(idx).head(),
573            ) && next.apply(ex.suffix(idx).head(), ex.suffix(idx).head_next()) ==> inv.apply(
574                ex.suffix(idx).head_next(),
575            ),
576    ensures
577        inv.apply(ex.suffix(i).head()),
578    decreases i,
579{
580    broadcast use {always_unfold, group_execution_suffix_lemmas};
581
582    if i != 0 {
583        implies_new_invariant_rec(ex, init, next, inv, proved_inv, (i - 1) as nat);
584    }
585}
586
587proof fn always_p_or_eventually_q_rec<T>(
588    ex: Execution<T>,
589    next: TempPred<T>,
590    p: TempPred<T>,
591    q: TempPred<T>,
592    i: nat,
593)
594    requires
595        always(p.and(next).implies(later(p).or(later(q)))).satisfied_by(ex),
596        always(next).satisfied_by(ex),
597        always(not(q)).satisfied_by(ex),
598        p.satisfied_by(ex),
599    ensures
600        p.satisfied_by(ex.suffix(i)),
601    decreases i,
602{
603    broadcast use {always_unfold, group_execution_suffix_lemmas};
604
605    if i != 0 {
606        always_p_or_eventually_q_rec::<T>(ex, next, p, q, (i - 1) as nat);
607    }
608}
609
610proof fn always_p_or_eventually_q<T>(
611    ex: Execution<T>,
612    next: TempPred<T>,
613    p: TempPred<T>,
614    q: TempPred<T>,
615)
616    requires
617        always(p.and(next).implies(later(p).or(later(q)))).satisfied_by(ex),
618        always(next).satisfied_by(ex),
619    ensures
620        always(p.implies(always(p).or(eventually(q)))).satisfied_by(ex),
621{
622    broadcast use {always_unfold, implies_apply, group_execution_suffix_lemmas};
623
624    assert forall|i| p.satisfied_by(#[trigger] ex.suffix(i)) implies always(p).satisfied_by(
625        ex.suffix(i),
626    ) || eventually(q).satisfied_by(ex.suffix(i)) by {
627        if !eventually(q).satisfied_by(ex.suffix(i)) {
628            assert forall|j| p.satisfied_by(#[trigger] ex.suffix(i).suffix(j)) by {
629                always_p_or_eventually_q_rec::<T>(ex.suffix(i), next, p, q, j);
630            };
631        }
632    };
633}
634
635proof fn next_preserves_inv_rec<T>(ex: Execution<T>, next: TempPred<T>, inv: TempPred<T>, i: nat)
636    requires
637        inv.satisfied_by(ex),
638        always(next).satisfied_by(ex),
639        always(inv.and(next).implies(later(inv))).satisfied_by(ex),
640    ensures
641        inv.satisfied_by(ex.suffix(i)),
642    decreases i,
643{
644    broadcast use {always_unfold, group_execution_suffix_lemmas};
645
646    if i != 0 {
647        next_preserves_inv_rec::<T>(ex, next, inv, (i - 1) as nat);
648    }
649}
650
651proof fn instantiate_entailed_always<T>(ex: Execution<T>, i: nat, spec: TempPred<T>, p: TempPred<T>)
652    requires
653        spec.satisfied_by(ex),
654        spec.implies(always(p)).satisfied_by(ex),
655    ensures
656        p.satisfied_by(ex.suffix(i)),
657{
658    broadcast use {always_unfold, implies_apply};
659
660}
661
662proof fn instantiate_entailed_leads_to<T>(
663    ex: Execution<T>,
664    i: nat,
665    spec: TempPred<T>,
666    p: TempPred<T>,
667    q: TempPred<T>,
668)
669    requires
670        spec.satisfied_by(ex),
671        spec.implies(p.leads_to(q)).satisfied_by(ex),
672    ensures
673        p.implies(eventually(q)).satisfied_by(ex.suffix(i)),
674{
675    broadcast use implies_apply;
676
677}
678
679} // verus!
680// Public lemmas about temporal logic for developers to simplify liveness/safety proofs.
681verus! {
682
683// Basic Rules of Temporal Logic Operators
684/// Lift `StatePred::and` to Verus meta-level.
685pub broadcast proof fn state_pred_and_apply_equality<T>(p: StatePred<T>, q: StatePred<T>, s: T)
686    ensures
687        #[trigger] p.and(q).apply(s) == (p.apply(s) && q.apply(s)),
688{
689}
690
691/// Lift `StatePred::or` to Verus meta-level.
692pub broadcast proof fn state_pred_or_apply_equality<T>(p: StatePred<T>, q: StatePred<T>, s: T)
693    ensures
694        #[trigger] p.or(q).apply(s) == (p.apply(s) || q.apply(s)),
695{
696}
697
698/// Lift `StatePred::not` to Verus meta-level.
699pub broadcast proof fn state_pred_not_apply_equality<T>(p: StatePred<T>, s: T)
700    ensures
701        #[trigger] p.not().apply(s) == !p.apply(s),
702{
703}
704
705/// Lift `StatePred::implies` to Verus meta-level.
706pub broadcast proof fn state_pred_implies_apply_equality<T>(p: StatePred<T>, q: StatePred<T>, s: T)
707    ensures
708        #[trigger] p.implies(q).apply(s) == (p.apply(s) ==> q.apply(s)),
709{
710}
711
712/// `StatePred::and` distributes over `lift_state`.
713///
714/// ## Postconditions
715/// - `lift_state(p ∧ q) == lift_state(p) ∧ lift_state(q)`
716pub broadcast proof fn lift_state_and_equality<T>(p: StatePred<T>, q: StatePred<T>)
717    ensures
718        #![trigger lift_state(p.and(q))]
719        #![trigger lift_state(p).and(lift_state(q))]
720        lift_state(p.and(q)) == lift_state(p).and(lift_state(q)),
721{
722}
723
724/// `StatePred::or` distributes over `lift_state`.
725///
726/// ## Postconditions
727/// - `lift_state(p ∨ q) == lift_state(p) ∨ lift_state(q)`
728pub broadcast proof fn lift_state_or_equality<T>(p: StatePred<T>, q: StatePred<T>)
729    ensures
730        #![trigger lift_state(p.or(q))]
731        #![trigger lift_state(p).or(lift_state(q))]
732        lift_state(p.or(q)) == lift_state(p).or(lift_state(q)),
733{
734}
735
736/// `StatePred::not` distributes over `lift_state`.
737///
738/// ## Postconditions
739/// - `lift_state(!p) == !lift_state(p)`
740pub broadcast proof fn lift_state_not_equality<T>(p: StatePred<T>)
741    ensures
742        #![trigger lift_state(p.not())]
743        #![trigger not(lift_state(p))]
744        lift_state(p.not()) == not(lift_state(p)),
745{
746}
747
748/// `StatePred::implies` distributes over `lift_state`.
749///
750/// ## Postconditions
751/// - `lift_state(p ⇒ q) == lift_state(p) ⇒ lift_state(q)`
752pub broadcast proof fn lift_state_implies_equality<T>(p: StatePred<T>, q: StatePred<T>)
753    ensures
754        #[trigger] lift_state(p.implies(q)) == lift_state(p).implies(lift_state(q)),
755{
756}
757
758/// `StatePred::and` distributes over `□`.
759///
760/// ## Postconditions
761/// - `□(p ∧ q) == □p ∧ □q`
762pub broadcast proof fn always_and_equality<T>(p: TempPred<T>, q: TempPred<T>)
763    ensures
764        #[trigger] always(p.and(q)) == always(p).and(always(q)),
765{
766    broadcast use always_unfold;
767
768    temp_pred_equality::<T>(always(p.and(q)), always(p).and(always(q)));
769}
770
771/// Lift entails `TempPred::and` to Verus meta-level.
772///
773/// If `⊧ p` and `⊧ q`, then `⊧ p ∧ q`.
774///
775/// ## Preconditions
776/// - `spec ⊧ p`
777/// - `spec ⊧ q`
778/// ## Postconditions
779/// - `spec ⊧ p ∧ q`
780pub broadcast proof fn entails_and_temp<T>(spec: TempPred<T>, p: TempPred<T>, q: TempPred<T>)
781    requires
782        spec.entails(p),
783        spec.entails(q),
784    ensures
785        #[trigger] spec.entails(p.and(q)),
786{
787    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.and(q).satisfied_by(ex) by {
788        implies_apply::<T>(ex, spec, p);
789        implies_apply::<T>(ex, spec, q);
790    };
791}
792
793/// Lift entails `TempPred::and` to Verus meta-level (reversed direction).
794///
795/// If `⊧ p ∧ q`, then `⊧ p` and `⊧ q`.
796///
797/// ## Preconditions
798/// - `spec ⊧ p ∧ q`
799/// ## Postconditions
800/// - `spec ⊧ p`
801/// - `spec ⊧ q`
802pub broadcast proof fn entails_and_temp_reverse<T>(
803    spec: TempPred<T>,
804    p: TempPred<T>,
805    q: TempPred<T>,
806)
807    requires
808        #[trigger] spec.entails(p.and(q)),
809    ensures
810        spec.entails(p),
811        spec.entails(q),
812{
813    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.satisfied_by(ex) by {
814        implies_apply::<T>(ex, spec, p.and(q));
815    };
816    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies q.satisfied_by(ex) by {
817        implies_apply::<T>(ex, spec, p.and(q));
818    };
819}
820
821/// Lift entails `TempPred::or` to Verus meta-level.
822///
823/// If `⊧ p` or `⊧ q`, then `⊧ p ∨ q`.
824///
825/// ## Preconditions
826/// - `spec ⊧ p` or `spec ⊧ q`
827/// ## Postconditions
828/// - `spec ⊧ p ∨ q`
829///
830/// NOTE: The other direction does not hold in general.
831pub broadcast proof fn entails_or_temp<T>(spec: TempPred<T>, p: TempPred<T>, q: TempPred<T>)
832    requires
833        spec.entails(p) || spec.entails(q),
834    ensures
835        #[trigger] spec.entails(p.or(q)),
836{
837    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.or(q).satisfied_by(ex) by {
838        if spec.entails(p) {
839            implies_apply::<T>(ex, spec, p);
840        } else {
841            implies_apply::<T>(ex, spec, q);
842        }
843    };
844}
845
846/// Lift entails `TempPred::not` to Verus meta-level (reversed direction).
847///
848/// If `⊧ !p`, then `!(⊧ p)`.
849///
850/// ## Preconditions
851/// - `spec ⊧ !p`
852/// ## Postconditions
853/// - `!(spec ⊧ p)`
854///
855/// NOTE: The other direction does not hold in general.
856pub broadcast proof fn entails_not_temp_reverse<T>(spec: TempPred<T>, p: TempPred<T>)
857    requires
858        #[trigger] spec.entails(not(p)),
859        spec != false_pred::<T>(),
860    ensures
861        !spec.entails(p),
862{
863    if forall|ex| !#[trigger] spec.satisfied_by(ex) {
864        temp_pred_equality::<T>(spec, false_pred::<T>());
865    }
866    let ex = choose|ex| spec.satisfied_by(ex);
867    assert(spec.implies(not(p)).satisfied_by(ex));
868    assert(!spec.implies(p).satisfied_by(ex));
869}
870
871/// Lift entails `TempPred::implies` to Verus meta-level.
872///
873/// If `⊧ p ⇒ q`, then `⊧ p` implies `⊧ q`.
874///
875/// ## Preconditions
876/// - `spec ⊧ (p ⇒ q)`
877/// ## Postconditions
878/// - `(spec ⊧ p) ⇒ (spec ⊧ q)`
879///
880/// NOTE: The other direction does not hold in general.
881pub broadcast proof fn entails_implies_temp_reverse<T>(
882    spec: TempPred<T>,
883    p: TempPred<T>,
884    q: TempPred<T>,
885)
886    requires
887        #[trigger] spec.entails(p.implies(q)),
888    ensures
889        spec.entails(p) ==> spec.entails(q),
890{
891    if spec.entails(p) {
892        assert forall|ex| #[trigger] spec.satisfied_by(ex) implies q.satisfied_by(ex) by {
893            implies_apply::<T>(ex, spec, p.implies(q));
894            implies_apply::<T>(ex, spec, p);
895        };
896    }
897}
898
899broadcast group group_definition_basics {
900    state_pred_and_apply_equality,
901    state_pred_or_apply_equality,
902    state_pred_not_apply_equality,
903    state_pred_implies_apply_equality,
904    lift_state_and_equality,
905    lift_state_or_equality,
906    lift_state_not_equality,
907    lift_state_implies_equality,
908    always_and_equality,
909    entails_and_temp,
910    entails_and_temp_reverse,
911    entails_or_temp,
912    entails_not_temp_reverse,
913    entails_implies_temp_reverse,
914}
915
916/// Double `□` can be simplified.
917///
918/// ## Postconditions
919/// - `□□p == □p`
920pub broadcast proof fn always_double_equality<T>(p: TempPred<T>)
921    ensures
922        #[trigger] always(always(p)) == always(p),
923{
924    broadcast use {always_unfold, group_execution_suffix_lemmas};
925
926    assert forall|ex| #[trigger] always(always(p)).satisfied_by(ex) implies always(p).satisfied_by(
927        ex,
928    ) by {
929        assert(always(p).satisfied_by(ex.suffix(0)));
930    }
931    temp_pred_equality::<T>(always(always(p)), always(p));
932}
933
934/// `StatePred::and` distributes over `□` and `lift_state`.
935///
936/// ## Postconditions
937/// - `□(lift_state(p ∧ q)) == □lift_state(p) ∧ □lift_state(q)`
938pub broadcast proof fn always_lift_state_and_equality<T>(p: StatePred<T>, q: StatePred<T>)
939    ensures
940        #[trigger] always(lift_state(p.and(q))) == always(lift_state(p)).and(always(lift_state(q))),
941{
942    broadcast use group_definition_basics;
943
944}
945
946/// Obviously `p ⇝ p` is valid.
947///
948/// ## Postconditions
949/// - `⊧ p ⇝ p`
950pub broadcast proof fn leads_to_self_temp<T>(p: TempPred<T>)
951    ensures
952        #[trigger] valid(p.leads_to(p)),
953{
954    broadcast use group_definition_basics;
955
956    assert forall|ex| #[trigger] always(p.implies(eventually(p))).satisfied_by(ex) by {
957        assert forall|i| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(p).satisfied_by(
958            ex.suffix(i),
959        ) by {
960            assert(ex.suffix(i) == ex.suffix(i).suffix(0));
961            eventually_proved_by_witness::<T>(ex.suffix(i), p, 0);
962        };
963    };
964}
965
966/// Entails is transitive.
967///
968/// ## Preconditions
969/// - `p ⊧ q`
970/// - `q ⊧ r`
971/// ## Postconditions
972/// - `p ⊧ r`
973pub proof fn entails_trans<T>(p: TempPred<T>, q: TempPred<T>, r: TempPred<T>)
974    requires
975        p.entails(q),
976        q.entails(r),
977    ensures
978        p.entails(r),
979{
980    assert forall|ex| p.satisfied_by(ex) implies r.satisfied_by(ex) by {
981        implies_apply::<T>(ex, p, q);
982        implies_apply::<T>(ex, q, r);
983    };
984}
985
986/// Introduce `□` to both sides of `⊧`.
987///
988/// ## Preconditions
989/// - `p ⊧ q`
990/// ## Postconditions
991/// - `□p ⊧ □q`
992pub broadcast proof fn entails_preserved_by_always<T>(p: TempPred<T>, q: TempPred<T>)
993    requires
994        p.entails(q),
995    ensures
996        #[trigger] always(p).entails(always(q)),
997{
998    broadcast use always_unfold;
999
1000    assert forall|ex| always(p).satisfied_by(ex) implies always(q).satisfied_by(ex) by {
1001        assert forall|i: nat| q.satisfied_by(#[trigger] ex.suffix(i)) by {
1002            implies_apply::<T>(ex.suffix(i), p, q);
1003        };
1004    };
1005}
1006
1007/// If `⊧ □p`, then `⊧ p`.
1008///
1009/// ## Preconditions
1010/// - `spec ⊧ □p`
1011/// ## Postconditions
1012/// - `spec ⊧ p`
1013pub proof fn eliminate_always<T>(spec: TempPred<T>, p: TempPred<T>)
1014    requires
1015        spec.entails(always(p)),
1016    ensures
1017        spec.entails(p),
1018{
1019    assert forall|ex| spec.satisfied_by(ex) implies #[trigger] p.satisfied_by(ex) by {
1020        implies_apply(ex, spec, always(p));
1021        assert(ex == ex.suffix(0));
1022    }
1023}
1024
1025/// If `⊧ □(p ⇒ q)`, then `⊧ p ⇝ q`.
1026///
1027/// ## Preconditions
1028/// - `spec ⊧ □(p ⇒ q)`
1029/// ## Postconditions
1030/// - `spec ⊧ p ⇝ q`
1031pub broadcast proof fn always_implies_to_leads_to<T>(
1032    spec: TempPred<T>,
1033    p: TempPred<T>,
1034    q: TempPred<T>,
1035)
1036    requires
1037        #[trigger] spec.entails(always(p.implies(q))),
1038    ensures
1039        spec.entails(p.leads_to(q)),
1040{
1041    broadcast use {always_unfold, implies_apply, group_definition_basics};
1042
1043    assert forall|ex| spec.satisfied_by(ex) implies #[trigger] p.leads_to(q).satisfied_by(ex) by {
1044        implies_apply(ex, spec, always(p.implies(q)));
1045        assert forall|i: nat| p.satisfied_by(#[trigger] ex.suffix(i)) implies eventually(
1046            q,
1047        ).satisfied_by(ex.suffix(i)) by {
1048            assert(ex.suffix(i) == ex.suffix(i).suffix(0));
1049        };
1050    };
1051}
1052
1053/// If entails `□p`, then entails `□(later(p))`.
1054///
1055/// ## Preconditions
1056/// - `spec ⊧ □p`
1057/// ## Postconditions
1058/// - `spec ⊧ □p'`
1059pub broadcast proof fn always_to_always_later<T>(spec: TempPred<T>, p: TempPred<T>)
1060    requires
1061        spec.entails(always(p)),
1062    ensures
1063        #[trigger] spec.entails(always(later(p))),
1064{
1065    broadcast use {always_unfold, group_execution_suffix_lemmas};
1066
1067    entails_trans(spec, always(p), always(later(p)));
1068}
1069
1070/// If `spec1 ⊧ p` and `spec2 ⊧ q`, then `spec1 ∧ spec2 ⊧ p ∧ q`.
1071///
1072/// ## Preconditions
1073/// - `spec1 ⊧ p`
1074/// - `spec2 ⊧ q`
1075/// ## Postconditions
1076/// - `spec1 ∧ spec2 ⊧ p ∧ q`
1077pub broadcast proof fn entails_and_different_temp<T>(
1078    spec1: TempPred<T>,
1079    spec2: TempPred<T>,
1080    p: TempPred<T>,
1081    q: TempPred<T>,
1082)
1083    requires
1084        spec1.entails(p),
1085        spec2.entails(q),
1086    ensures
1087        #[trigger] spec1.and(spec2).entails(p.and(q)),
1088{
1089    assert forall|ex| #[trigger] spec1.and(spec2).satisfied_by(ex) implies p.and(q).satisfied_by(
1090        ex,
1091    ) by {
1092        implies_apply::<T>(ex, spec1, p);
1093        implies_apply::<T>(ex, spec2, q);
1094    };
1095}
1096
1097/// If `p ⇒ q` for all executions, then `p ⇝ q`.
1098///
1099/// ## Preconditions
1100/// - `p ⊧ q`
1101/// ## Postconditions
1102/// - `spec ⊧ p ⇝ q`
1103///
1104/// NOTE: there is no constraint on `spec`, it can be true_pred().
1105pub proof fn entails_implies_leads_to<T>(spec: TempPred<T>, p: TempPred<T>, q: TempPred<T>)
1106    requires
1107        p.entails(q),
1108    ensures
1109        spec.entails(p.leads_to(q)),
1110{
1111    valid_p_implies_always_p(p.implies(q));
1112    always_implies_to_leads_to(spec, p, q);
1113}
1114
1115/// Weaken `□` by `⇒`.
1116///
1117/// ## Preconditions
1118/// - `⊧ p ⇒ q`
1119/// - `spec ⊧ □p`
1120/// ## Postconditions
1121/// - `spec ⊧ □q`
1122pub proof fn always_weaken<T>(spec: TempPred<T>, p: TempPred<T>, q: TempPred<T>)
1123    requires
1124        valid(p.implies(q)),
1125        spec.entails(always(p)),
1126    ensures
1127        spec.entails(always(q)),
1128{
1129    entails_preserved_by_always::<T>(p, q);
1130    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies always(q).satisfied_by(ex) by {
1131        implies_apply::<T>(ex, spec, always(p));
1132        implies_apply::<T>(ex, always(p), always(q));
1133    };
1134}
1135
1136/// If `⊧ p` and `⊧ p ⇝ q`, then `⊧ ◊q`.
1137///
1138/// ## Preconditions
1139/// - `spec ⊧ p`
1140/// - `spec ⊧ p ⇝ q`
1141/// ## Postconditions
1142/// - `spec ⊧ ◊q`
1143pub broadcast proof fn leads_to_apply<T>(spec: TempPred<T>, p: TempPred<T>, q: TempPred<T>)
1144    requires
1145        spec.entails(p),
1146        #[trigger] spec.entails(p.leads_to(q)),
1147    ensures
1148        spec.entails(eventually(q)),
1149{
1150    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies eventually(q).satisfied_by(ex) by {
1151        implies_apply::<T>(ex, spec, p);
1152        implies_apply::<T>(ex, spec, p.leads_to(q));
1153        leads_to_unfold::<T>(ex, p, q);
1154        assert(ex == ex.suffix(0));
1155        implies_apply::<T>(ex, p, eventually(q));
1156    };
1157}
1158
1159/// Leads to is transitive.
1160///
1161/// ## Preconditions
1162/// - `spec ⊧ p ⇝ q`
1163/// - `spec ⊧ q ⇝ r`
1164/// ## Postconditions
1165/// - `spec ⊧ p ⇝ r`
1166pub proof fn leads_to_trans<T>(spec: TempPred<T>, p: TempPred<T>, q: TempPred<T>, r: TempPred<T>)
1167    requires
1168        spec.entails(p.leads_to(q)),
1169        spec.entails(q.leads_to(r)),
1170    ensures
1171        spec.entails(p.leads_to(r)),
1172{
1173    broadcast use group_definition_basics;
1174
1175    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(r).satisfied_by(ex) by {
1176        assert forall|i: nat| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(
1177            r,
1178        ).satisfied_by(ex.suffix(i)) by {
1179            entails_apply(ex, spec, p.leads_to(q));
1180            always_unfold(ex, p.implies(eventually(q)));
1181            implies_apply(ex.suffix(i), p, eventually(q));
1182            eventually_unfold(ex.suffix(i), q);
1183            let q_witness_idx = eventually_choose_witness(ex.suffix(i), q);
1184
1185            assert(ex.suffix(i + q_witness_idx) == ex.suffix(i).suffix(q_witness_idx));
1186
1187            entails_apply(ex, spec, q.leads_to(r));
1188            always_unfold(ex, q.implies(eventually(r)));
1189            implies_apply(ex.suffix(i + q_witness_idx), q, eventually(r));
1190
1191            eventually_propagate_backwards(ex.suffix(i), r, q_witness_idx);
1192        }
1193    };
1194}
1195
1196/// Weaken `□` lifted state predicate by `⇒`.
1197///
1198/// ## Preconditions
1199/// - `∀ s. p(s) ⇒ q(s)`
1200/// - `spec ⊧ □lift_state(p)`
1201///
1202/// ## Postconditions
1203/// - `spec ⊧ □lift_state(q)`
1204pub proof fn always_lift_state_weaken<T>(spec: TempPred<T>, p: StatePred<T>, q: StatePred<T>)
1205    requires
1206        forall|s: T| #[trigger] p.apply(s) ==> q.apply(s),
1207        spec.entails(always(lift_state(p))),
1208    ensures
1209        spec.entails(always(lift_state(q))),
1210{
1211    always_weaken::<T>(spec, lift_state(p), lift_state(q));
1212}
1213
1214/// Introduce `□` to both sides of `⇒`.
1215///
1216/// ## Preconditions
1217/// - `spec ⊧ □(p ⇒ q)`
1218/// ## Postconditions
1219/// - `spec ⊧ □(□p ⇒ □q)`
1220pub proof fn always_implies_preserved_by_always<T>(
1221    spec: TempPred<T>,
1222    p: TempPred<T>,
1223    q: TempPred<T>,
1224)
1225    requires
1226        spec.entails(always(p.implies(q))),
1227    ensures
1228        spec.entails(always(always(p).implies(always(q)))),
1229{
1230    broadcast use group_tla_rules;
1231
1232    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies always(
1233        always(p).implies(always(q)),
1234    ).satisfied_by(ex) by {
1235        assert forall|i| #[trigger] always(p).satisfied_by(ex.suffix(i)) implies always(
1236            q,
1237        ).satisfied_by(ex.suffix(i)) by {
1238            assert forall|j| #[trigger] q.satisfied_by(ex.suffix(i).suffix(j)) by {
1239                implies_apply::<T>(ex, spec, always(p.implies(q)));
1240                assert(ex.suffix(i + j) == ex.suffix(i).suffix(j));
1241                implies_apply::<T>(ex.suffix(i).suffix(j), p, q);
1242            };
1243        };
1244    };
1245}
1246
1247/// Combine the premises of two `⇝` using `∨`.
1248///
1249/// ## Preconditions
1250///  - `spec ⊧ p ⇝ r`
1251///  - `spec ⊧ q ⇝ r`
1252/// ## Postconditions
1253///  - `spec ⊧ (p ∨ q) ⇝ r`
1254pub broadcast proof fn or_leads_to_combine<T>(
1255    spec: TempPred<T>,
1256    p: TempPred<T>,
1257    q: TempPred<T>,
1258    r: TempPred<T>,
1259)
1260    requires
1261        spec.entails(p.leads_to(r)),
1262        spec.entails(q.leads_to(r)),
1263    ensures
1264        #[trigger] spec.entails(p.or(q).leads_to(r)),
1265{
1266    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.or(q).leads_to(r).satisfied_by(
1267        ex,
1268    ) by {
1269        assert forall|i| #[trigger] p.or(q).satisfied_by(ex.suffix(i)) implies eventually(
1270            r,
1271        ).satisfied_by(ex.suffix(i)) by {
1272            implies_apply::<T>(ex, spec, p.leads_to(r));
1273            implies_apply::<T>(ex, spec, q.leads_to(r));
1274            leads_to_unfold::<T>(ex, p, r);
1275            leads_to_unfold::<T>(ex, q, r);
1276        };
1277    };
1278}
1279
1280/// Prove `p ⇝ r` by case analysis on `q`.
1281///
1282/// ## Preconditions
1283///  - `spec ⊧ (p ∧ q) ⇝ r`
1284///  - `spec ⊧ (p ∧ ~q) ⇝ r`
1285/// ## Postconditions
1286///  - `spec ⊧ p ⇝ r`
1287pub proof fn or_leads_to_case_analysis<T>(
1288    spec: TempPred<T>,
1289    p: TempPred<T>,
1290    q: TempPred<T>,
1291    r: TempPred<T>,
1292)
1293    requires
1294        spec.entails(p.and(q).leads_to(r)),
1295        spec.entails(p.and(not(q)).leads_to(r)),
1296    ensures
1297        spec.entails(p.leads_to(r)),
1298{
1299    broadcast use group_definition_basics;
1300
1301    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(r).satisfied_by(ex) by {
1302        if spec.satisfied_by(ex) {
1303            assert(spec.implies(p.and(q).leads_to(r)).satisfied_by(ex));
1304            assert(spec.implies(p.and(not(q)).leads_to(r)).satisfied_by(ex));
1305
1306            leads_to_unfold(ex, p.and(q), r);
1307            leads_to_unfold(ex, p.and(not(q)), r);
1308
1309            assert forall|i| p.implies(eventually(r)).satisfied_by(#[trigger] ex.suffix(i)) by {}
1310        }
1311    }
1312}
1313
1314/// Combine the conclusions of two `⇝` if the conclusions are stable.
1315///
1316/// ## Preconditions
1317///  - `spec ⊧ p ⇝ □q`
1318///  - `spec ⊧ p ⇝ □r`
1319/// ## Postconditions
1320/// - `spec ⊧ p ⇝ □(q ∧ r)`
1321pub broadcast proof fn leads_to_always_combine<T>(
1322    spec: TempPred<T>,
1323    p: TempPred<T>,
1324    q: TempPred<T>,
1325    r: TempPred<T>,
1326)
1327    requires
1328        spec.entails(p.leads_to(always(q))),
1329        spec.entails(p.leads_to(always(r))),
1330    ensures
1331        #![trigger spec.entails(p.leads_to(always(q).and(always(r))))]
1332        #![trigger spec.entails(p.leads_to(always(q.and(r))))]
1333        spec.entails(p.leads_to(always(q.and(r)))),
1334        spec.entails(p.leads_to(always(q).and(always(r)))),
1335{
1336    broadcast use group_definition_basics;
1337
1338    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(
1339        always(q.and(r)),
1340    ).satisfied_by(ex) by {
1341        assert forall|i| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(
1342            always(q.and(r)),
1343        ).satisfied_by(ex.suffix(i)) by {
1344            implies_apply::<T>(ex, spec, p.leads_to(always(q)));
1345            implies_apply::<T>(ex, spec, p.leads_to(always(r)));
1346
1347            implies_apply::<T>(ex.suffix(i), p, eventually(always(q)));
1348            implies_apply::<T>(ex.suffix(i), p, eventually(always(r)));
1349
1350            let witness_q_idx = eventually_choose_witness::<T>(ex.suffix(i), always(q));
1351            let witness_r_idx = eventually_choose_witness::<T>(ex.suffix(i), always(r));
1352
1353            if witness_q_idx < witness_r_idx {
1354                always_propagate_forwards::<T>(
1355                    ex.suffix(i).suffix(witness_q_idx),
1356                    q,
1357                    (witness_r_idx - witness_q_idx) as nat,
1358                );
1359                assert(ex.suffix(i).suffix(witness_r_idx) == ex.suffix(i).suffix(
1360                    witness_q_idx,
1361                ).suffix((witness_r_idx - witness_q_idx) as nat));
1362                eventually_proved_by_witness(ex.suffix(i), always(q.and(r)), witness_r_idx);
1363            } else {
1364                always_propagate_forwards::<T>(
1365                    ex.suffix(i).suffix(witness_r_idx),
1366                    r,
1367                    (witness_q_idx - witness_r_idx) as nat,
1368                );
1369                assert(ex.suffix(i).suffix(witness_q_idx) == ex.suffix(i).suffix(
1370                    witness_r_idx,
1371                ).suffix((witness_q_idx - witness_r_idx) as nat));
1372                eventually_proved_by_witness(ex.suffix(i), always(q.and(r)), witness_q_idx);
1373            }
1374        };
1375    };
1376    always_and_equality(q, r);
1377}
1378
1379/// Prove `p ⇝ □q` by showing that `q` is preserved.
1380///
1381/// ## Preconditions
1382///  - `spec ⊧ □(q ∧ next ⇒ q')`
1383///  - `spec ⊧ □next`
1384///  - `spec ⊧ p ⇝ q`
1385/// ## Postconditions
1386///  - `spec ⊧ p ⇝ □q`
1387pub proof fn leads_to_stable<T>(
1388    spec: TempPred<T>,
1389    next: TempPred<T>,
1390    p: TempPred<T>,
1391    q: TempPred<T>,
1392)
1393    requires
1394        spec.entails(always(q.and(next).implies(later(q)))),
1395        spec.entails(always(next)),
1396        spec.entails(p.leads_to(q)),
1397    ensures
1398        spec.entails(p.leads_to(always(q))),
1399{
1400    broadcast use {always_unfold, always_propagate_forwards, group_definition_basics};
1401
1402    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(always(q)).satisfied_by(
1403        ex,
1404    ) by {
1405        assert forall|i| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(
1406            always(q),
1407        ).satisfied_by(ex.suffix(i)) by {
1408            implies_apply::<T>(ex, spec, p.leads_to(q));
1409            leads_to_unfold::<T>(ex, p, q);
1410            implies_apply::<T>(ex.suffix(i), p, eventually(q));
1411            let witness_idx = eventually_choose_witness::<T>(ex.suffix(i), q);
1412
1413            implies_apply::<T>(ex, spec, always(q.and(next).implies(later(q))));
1414            always_propagate_forwards::<T>(
1415                ex.suffix(i),
1416                q.and(next).implies(later(q)),
1417                witness_idx,
1418            );
1419
1420            implies_apply::<T>(ex, spec, always(next));
1421            always_propagate_forwards::<T>(ex.suffix(i), next, witness_idx);
1422
1423            assert forall|j| #[trigger]
1424                q.satisfied_by(ex.suffix(i).suffix(witness_idx).suffix(j)) by {
1425                assert forall|idx|
1426                    q.satisfied_by(#[trigger] ex.suffix(i).suffix(witness_idx).suffix(idx))
1427                        && next.satisfied_by(
1428                        ex.suffix(i).suffix(witness_idx).suffix(idx),
1429                    ) implies q.satisfied_by(ex.suffix(i).suffix(witness_idx).suffix(idx + 1)) by {
1430                    implies_apply::<T>(
1431                        ex.suffix(i).suffix(witness_idx).suffix(idx),
1432                        q.and(next),
1433                        later(q),
1434                    );
1435                    assert(ex.suffix(i).suffix(witness_idx).suffix(idx + 1) == ex.suffix(i).suffix(
1436                        witness_idx,
1437                    ).suffix(idx).suffix(1));
1438                };
1439                next_preserves_inv_rec::<T>(ex.suffix(i).suffix(witness_idx), next, q, j);
1440            };
1441
1442            eventually_proved_by_witness::<T>(ex.suffix(i), always(q), witness_idx);
1443        };
1444    };
1445}
1446
1447/// Sandwich `⇝` with `∨ r`.
1448///
1449/// ## Preconditions
1450/// - `spec ⊧ p ⇝ q`
1451/// ## Postconditions
1452/// - `spec ⊧ p ∨ r ⇝ q ∨ r`
1453pub broadcast proof fn leads_to_framed_by_or<T>(
1454    spec: TempPred<T>,
1455    p: TempPred<T>,
1456    q: TempPred<T>,
1457    r: TempPred<T>,
1458)
1459    requires
1460        spec.entails(p.leads_to(q)),
1461    ensures
1462        #[trigger] spec.entails(p.or(r).leads_to(q.or(r))),
1463{
1464    broadcast use {implies_apply, group_execution_suffix_lemmas, group_definition_basics};
1465
1466    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.or(r).leads_to(
1467        q.or(r),
1468    ).satisfied_by(ex) by {
1469        assert forall|i| #[trigger] p.or(r).satisfied_by(ex.suffix(i)) implies eventually(
1470            q.or(r),
1471        ).satisfied_by(ex.suffix(i)) by {
1472            implies_apply(ex, spec, p.leads_to(q));
1473            leads_to_unfold(ex, p, q);
1474            if p.satisfied_by(ex.suffix(i)) {
1475                let witness_idx = eventually_choose_witness(ex.suffix(i), q);
1476                eventually_proved_by_witness(ex.suffix(i), q.or(r), witness_idx);
1477            } else {
1478                let witness_idx = 0;
1479                eventually_proved_by_witness(ex.suffix(i), q.or(r), witness_idx);
1480            }
1481        }
1482    }
1483}
1484
1485/// Combine two `⇝` with a shortcut.
1486///
1487/// ## Preconditions
1488/// - `spec ⊧ p ⇝ q ∨ s`
1489/// - `spec ⊧ q ⇝ r ∨ s`
1490/// ## Postconditions
1491/// - `spec ⊧ p ⇝ r ∨ s`
1492pub proof fn leads_to_shortcut_temp<T>(
1493    spec: TempPred<T>,
1494    p: TempPred<T>,
1495    q: TempPred<T>,
1496    r: TempPred<T>,
1497    s: TempPred<T>,
1498)
1499    requires
1500        spec.entails(p.leads_to(q.or(s))),
1501        spec.entails(q.leads_to(r.or(s))),
1502    ensures
1503        spec.entails(p.leads_to(r.or(s))),
1504{
1505    leads_to_framed_by_or(spec, q, r.or(s), s);
1506    temp_pred_equality(r.or(s).or(s), r.or(s));
1507    leads_to_trans(spec, p, q.or(s), r.or(s));
1508}
1509
1510/// If `⊧ □(lift_state(p))` and `⊧ □(lift_state(q))`, then `⊧ □(lift_state(p ∧ q))`.
1511///
1512/// ## Preconditions
1513///  - `spec ⊧ □lift_state(p)`
1514///  - `spec ⊧ □lift_state(q)`
1515/// ## Postconditions
1516///  - `spec ⊧ □lift_state(p ∧ q)`
1517pub broadcast proof fn entails_always_lift_state_and<T>(
1518    spec: TempPred<T>,
1519    p: StatePred<T>,
1520    q: StatePred<T>,
1521)
1522    requires
1523        spec.entails(always(lift_state(p))),
1524        spec.entails(always(lift_state(q))),
1525    ensures
1526        #[trigger] spec.entails(always(lift_state(p.and(q)))),
1527{
1528    broadcast use group_definition_basics;
1529
1530}
1531
1532/// Eliminate and split two state predicates under `□`.
1533///
1534/// ## Preconditions
1535/// - `spec ⊧ □lift_state(p ∧ q)`
1536/// ## Postconditions
1537/// - `spec ⊧ □lift_state(p)`
1538/// - `spec ⊧ □lift_state(q)`
1539pub broadcast proof fn entails_always_lift_state_and_elim<T>(
1540    spec: TempPred<T>,
1541    p: StatePred<T>,
1542    q: StatePred<T>,
1543)
1544    requires
1545        #[trigger] spec.entails(always(lift_state(p.and(q)))),
1546    ensures
1547        spec.entails(always(lift_state(p))),
1548        spec.entails(always(lift_state(q))),
1549{
1550    broadcast use group_definition_basics;
1551
1552}
1553
1554// Rules about quantifiers.
1555/// Lift the `exists` outside `lift_state`.
1556///
1557/// ## Postconditions
1558/// - `lift_state(∃ a: A. p(a)) == ∃ a: A. lift_state(p(a))`
1559pub broadcast proof fn lift_state_exists_equality<T, A>(a_to_state_pred: spec_fn(A) -> StatePred<T>)
1560    ensures
1561        #[trigger] lift_state_exists(a_to_state_pred) == tla_exists(
1562            |a| lift_state(a_to_state_pred(a)),
1563        ),
1564{
1565    let p = lift_state_exists(a_to_state_pred);
1566    let q = tla_exists(|a| lift_state(a_to_state_pred(a)));
1567    let partial_p = |t| exists|a| #[trigger] a_to_state_pred(a).apply(t);
1568    let partial_q = |a| lift_state(a_to_state_pred(a));
1569    assert forall|ex| p.satisfied_by(ex) implies q.satisfied_by(ex) by {
1570        assert(exists|a| #[trigger] a_to_state_pred(a).apply(ex.head()));
1571        let witness_a = choose|a| #[trigger] a_to_state_pred(a).apply(ex.head());
1572        assert(partial_q(witness_a).satisfied_by(ex));
1573    };
1574
1575    temp_pred_equality::<T>(p, q);
1576}
1577
1578/// Lift the `□` outside `tla_forall` if the function is previously wrapped by an `□`.
1579///
1580/// ## Postconditions
1581/// - `∀ a:A. □P(a) == □(∀ a:A. P(a)))`
1582///
1583/// NOTE: Verus may not able to infer that `(|a| func(a))(a)` equals `func(a)`.
1584///       Please turn to lemma [`tla_forall_always_equality_variant`] for troubleshooting.
1585pub proof fn tla_forall_always_equality<T, A>(a_to_temp_pred: spec_fn(A) -> TempPred<T>)
1586    ensures
1587        tla_forall(|a: A| always(a_to_temp_pred(a))) == always(tla_forall(a_to_temp_pred)),
1588{
1589    broadcast use {always_unfold, tla_forall_unfold};
1590
1591    let a_to_always_p = |a: A| always(a_to_temp_pred(a));
1592
1593    assert forall|ex| #[trigger] tla_forall(a_to_always_p).satisfied_by(ex) implies always(
1594        tla_forall(a_to_temp_pred),
1595    ).satisfied_by(ex) by {
1596        assert forall|i| #[trigger] tla_forall(a_to_temp_pred).satisfied_by(ex.suffix(i)) by {
1597            assert forall|a| #[trigger] a_to_temp_pred(a).satisfied_by(ex.suffix(i)) by {
1598                assert(a_to_always_p(a).satisfied_by(ex));
1599            };
1600        };
1601    };
1602
1603    temp_pred_equality::<T>(
1604        tla_forall(|a: A| always(a_to_temp_pred(a))),
1605        always(tla_forall(a_to_temp_pred)),
1606    );
1607}
1608
1609pub proof fn tla_forall_always_equality_variant<T, A>(
1610    a_to_always: spec_fn(A) -> TempPred<T>,
1611    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
1612)
1613    requires
1614        forall|a: A|
1615            #![trigger a_to_always(a)]
1616            a_to_always(a).entails((|a: A| always(a_to_temp_pred(a)))(a)) && ((|a: A|
1617                always(a_to_temp_pred(a)))(a)).entails(a_to_always(a)),
1618    ensures
1619        tla_forall(a_to_always) == always(tla_forall(a_to_temp_pred)),
1620{
1621    a_to_temp_pred_equality::<T, A>(a_to_always, |a: A| always(a_to_temp_pred(a)));
1622    temp_pred_equality::<T>(tla_forall(a_to_always), tla_forall(|a: A| always(a_to_temp_pred(a))));
1623    tla_forall_always_equality::<T, A>(a_to_temp_pred);
1624}
1625
1626/// If `forall a. P(a)` holds, then `P` holds for any particular `a`.
1627///
1628/// ## Postconditions
1629/// - `∀ a: A. P(a) ⊧ P(a)`
1630pub broadcast proof fn tla_forall_apply<T, A>(a_to_temp_pred: spec_fn(A) -> TempPred<T>, a: A)
1631    ensures
1632        #[trigger] tla_forall(a_to_temp_pred).entails(a_to_temp_pred(a)),
1633{
1634    broadcast use tla_forall_unfold;
1635
1636}
1637
1638// Used to be named as always_tla_forall_apply
1639/// If `⊧ □(∀ a. P(a))`, then `⊧ □(P(a))` for any particular `a`.
1640///
1641/// ## Preconditions
1642/// - `spec ⊧ □(∀ a: A. P(a))`
1643/// ## Postconditions
1644/// - `spec ⊧ □(P(a))`
1645pub proof fn use_always_tla_forall<T, A>(
1646    spec: TempPred<T>,
1647    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
1648    a: A,
1649)
1650    requires
1651        spec.entails(always(tla_forall(a_to_temp_pred))),
1652    ensures
1653        spec.entails(always(a_to_temp_pred(a))),
1654{
1655    entails_preserved_by_always(tla_forall(a_to_temp_pred), a_to_temp_pred(a));
1656    entails_trans(spec, always(tla_forall(a_to_temp_pred)), always(a_to_temp_pred(a)));
1657}
1658
1659/// If ⊧ `P(a)` for all `a`, then ⊧ `∀ a. P(a)`.
1660///
1661/// ## Preconditions
1662/// - `forall a: A. spec ⊧ P(a)`
1663///
1664/// ## Postconditions
1665/// - `spec ⊧ ∀ a: A. P(a)`
1666pub broadcast proof fn spec_entails_tla_forall<T, A>(
1667    spec: TempPred<T>,
1668    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
1669)
1670    requires
1671        forall|a: A| spec.entails(#[trigger] a_to_temp_pred(a)),
1672    ensures
1673        #[trigger] spec.entails(tla_forall(a_to_temp_pred)),
1674{
1675    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies tla_forall(
1676        a_to_temp_pred,
1677    ).satisfied_by(ex) by {
1678        assert forall|a| #[trigger] a_to_temp_pred(a).satisfied_by(ex) by {
1679            implies_apply::<T>(ex, spec, a_to_temp_pred(a));
1680        };
1681    };
1682}
1683
1684/// If ⊧ `□(P(a))` for all `a`, then ⊧ `□(∀ a. P(a))`.
1685///
1686/// ## Preconditions
1687/// - `forall a: A. spec ⊧ □P(a)`
1688/// ## Postconditions
1689/// - `spec ⊧ □(∀ a: A. P(a))`
1690pub proof fn spec_entails_always_tla_forall<T, A>(
1691    spec: TempPred<T>,
1692    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
1693)
1694    requires
1695        forall|a: A| spec.entails(always(#[trigger] a_to_temp_pred(a))),
1696    ensures
1697        spec.entails(always(tla_forall(a_to_temp_pred))),
1698{
1699    let a_to_always = |a: A| always(a_to_temp_pred(a));
1700    spec_entails_tla_forall(spec, a_to_always);
1701    tla_forall_always_equality_variant::<T, A>(a_to_always, a_to_temp_pred);
1702}
1703
1704/// If ⊧ `□(p ⇒ P(a))` for all `a`, then ⊧ `□(p ⇒ forall a. P(a))`.
1705///
1706/// ## Preconditions
1707///  - `forall a: A. spec ⊧ □(p ⇒ P(a))`
1708/// ## Postconditions
1709///  - `spec ⊧ □(p ⇒ (∀ a: A. P(a)))`
1710pub broadcast proof fn always_implies_forall_intro<T, A>(
1711    spec: TempPred<T>,
1712    p: TempPred<T>,
1713    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
1714)
1715    requires
1716        forall|a: A| #[trigger] spec.entails(always(p.implies(a_to_temp_pred(a)))),
1717    ensures
1718        #[trigger] spec.entails(always(p.implies(tla_forall(a_to_temp_pred)))),
1719{
1720    let a_to_always_p_implies_q = |a: A| always(p.implies(a_to_temp_pred(a)));
1721    spec_entails_tla_forall::<T, A>(spec, a_to_always_p_implies_q);
1722    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies always(
1723        p.implies(tla_forall(a_to_temp_pred)),
1724    ).satisfied_by(ex) by {
1725        implies_apply::<T>(ex, spec, tla_forall(a_to_always_p_implies_q));
1726        tla_forall_always_implies_equality2::<T, A>(p, a_to_temp_pred)
1727    };
1728}
1729
1730/// If ⊧ `P(a) ⇝ q` for all `a`, then ⊧ `exists a. P(a) leads_to q`.
1731///
1732/// ## Preconditions
1733///  - `forall a: A. spec ⊧ P(a) ⇝ q`
1734/// ## Postconditions
1735///  - `spec ⊧ (∃ a: A. P(a)) ⇝ q`
1736pub broadcast proof fn tla_exists_leads_to_intro<T, A>(
1737    spec: TempPred<T>,
1738    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
1739    q: TempPred<T>,
1740)
1741    requires
1742        forall|a: A| #[trigger] spec.entails(a_to_temp_pred(a).leads_to(q)),
1743    ensures
1744        #[trigger] spec.entails(tla_exists(a_to_temp_pred).leads_to(q)),
1745{
1746    let a_to_temp_pred_leads_to_q = |a: A| a_to_temp_pred(a).leads_to(q);
1747    spec_entails_tla_forall::<T, A>(spec, a_to_temp_pred_leads_to_q);
1748    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies tla_exists(a_to_temp_pred).leads_to(
1749        q,
1750    ).satisfied_by(ex) by {
1751        implies_apply::<T>(ex, spec, tla_forall(a_to_temp_pred_leads_to_q));
1752        tla_forall_leads_to_equality1::<T, A>(a_to_temp_pred, q);
1753    };
1754}
1755
1756/// If ⊧ `forall a. P(a)`, then ⊧ `P(a)` for any particular `a`.
1757///
1758/// ## Preconditions
1759///  - `spec ⊧ (∀ a: A. P(a))`
1760/// ## Postconditions
1761///  - `spec ⊧ P(a)`
1762pub proof fn use_tla_forall<T, A>(
1763    spec: TempPred<T>,
1764    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
1765    a: A,
1766)
1767    requires
1768        spec.entails(tla_forall(a_to_temp_pred)),
1769    ensures
1770        spec.entails(a_to_temp_pred(a)),
1771{
1772    assert forall|ex: Execution<T>| #[trigger] spec.satisfied_by(ex) implies (a_to_temp_pred(
1773        a,
1774    )).satisfied_by(ex) by {
1775        entails_apply(ex, spec, tla_forall(a_to_temp_pred));
1776        assert(spec.implies(tla_forall(a_to_temp_pred)).satisfied_by(ex));
1777    };
1778}
1779
1780pub broadcast proof fn entails_tla_exists_by_witness<T, A>(
1781    spec: TempPred<T>,
1782    p: spec_fn(A) -> TempPred<T>,
1783    a: A,
1784)
1785    requires
1786        #[trigger] spec.entails(p(a)),
1787    ensures
1788        spec.entails(tla_exists(p)),
1789{
1790    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies tla_exists(p).satisfied_by(ex) by {
1791        implies_apply::<T>(ex, spec, p(a));
1792        tla_exists_unfold::<T, A>(ex, p);
1793    };
1794}
1795
1796pub proof fn implies_tla_exists_by_witness<T, A>(
1797    spec: TempPred<T>,
1798    p: TempPred<T>,
1799    q: spec_fn(A) -> TempPred<T>,
1800    a: A,
1801)
1802    requires
1803        spec.entails(p.implies(q(a))),
1804    ensures
1805        spec.entails(p.implies(tla_exists(q))),
1806{
1807    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.implies(
1808        tla_exists(q),
1809    ).satisfied_by(ex) by {
1810        implies_apply(ex, spec, p.implies(q(a)));
1811    };
1812}
1813
1814pub broadcast proof fn implies_tla_exists_intro<T, A>(
1815    spec: TempPred<T>,
1816    p: TempPred<T>,
1817    q: spec_fn(A) -> TempPred<T>,
1818)
1819    requires
1820        exists|a: A| #[trigger] spec.entails(p.implies(q(a))),
1821    ensures
1822        #[trigger] spec.entails(p.implies(tla_exists(q))),
1823{
1824    let witness = choose|a: A| #[trigger] spec.entails(p.implies(q(a)));
1825    implies_tla_exists_by_witness(spec, p, q, witness);
1826}
1827
1828pub proof fn leads_to_tla_exists_by_witness<T, A>(
1829    spec: TempPred<T>,
1830    p: TempPred<T>,
1831    q: spec_fn(A) -> TempPred<T>,
1832    a: A,
1833)
1834    requires
1835        spec.entails(p.leads_to(q(a))),
1836    ensures
1837        spec.entails(p.leads_to(tla_exists(q))),
1838{
1839    assert forall|ex| #[trigger] always(q(a).implies(tla_exists(q))).satisfied_by(ex) by {
1840        assert forall|i: nat| q(a).implies(tla_exists(q)).satisfied_by(ex.suffix(i)) by {
1841            if q(a).satisfied_by(ex.suffix(i)) {
1842                tla_exists_proved_by_witness(ex.suffix(i), q, a);
1843            }
1844        };
1845    };
1846    leads_to_weaken(spec, p, q(a), p, tla_exists(q));
1847}
1848
1849pub broadcast proof fn leads_to_tla_exists_intro<T, A>(
1850    spec: TempPred<T>,
1851    p: TempPred<T>,
1852    q: spec_fn(A) -> TempPred<T>,
1853)
1854    requires
1855        exists|a: A| #[trigger] spec.entails(p.leads_to(q(a))),
1856    ensures
1857        #[trigger] spec.entails(p.leads_to(tla_exists(q))),
1858{
1859    let witness = choose|a: A| #[trigger] spec.entails(p.leads_to(q(a)));
1860    leads_to_tla_exists_by_witness(spec, p, q, witness);
1861}
1862
1863pub broadcast proof fn lift_state_exists_leads_to_intro<T, A>(
1864    spec: TempPred<T>,
1865    a_to_temp_pred: spec_fn(A) -> StatePred<T>,
1866    q: TempPred<T>,
1867)
1868    requires
1869        forall|a: A| #[trigger] spec.entails(lift_state(a_to_temp_pred(a)).leads_to(q)),
1870    ensures
1871        #[trigger] spec.entails(lift_state_exists(a_to_temp_pred).leads_to(q)),
1872{
1873    lift_state_exists_equality(a_to_temp_pred);
1874    let lifted_a_to_temp_pred = |a: A| lift_state(a_to_temp_pred(a));
1875    tla_exists_leads_to_intro(spec, lifted_a_to_temp_pred, q);
1876}
1877
1878pub broadcast proof fn state_exists_intro<T, A>(a_to_temp_pred: spec_fn(A) -> StatePred<T>, s: T)
1879    requires
1880        exists|a: A| #[trigger] a_to_temp_pred(a).apply(s),
1881    ensures
1882        #[trigger] StatePred::state_exists(a_to_temp_pred).apply(s),
1883{
1884}
1885
1886pub broadcast proof fn lift_state_exists_absorb_equality<T, A>(
1887    a_to_state_pred: spec_fn(A) -> StatePred<T>,
1888    state_pred: StatePred<T>,
1889)
1890    ensures
1891        #[trigger] lift_state_exists(a_to_state_pred).and(lift_state(state_pred))
1892            == lift_state_exists(StatePred::absorb(a_to_state_pred, state_pred)),
1893{
1894    broadcast use group_definition_basics;
1895
1896    let lhs = lift_state_exists(a_to_state_pred).and(lift_state(state_pred));
1897    let rhs = lift_state_exists(StatePred::absorb(a_to_state_pred, state_pred));
1898
1899    assert forall|ex| lhs.satisfied_by(ex) == rhs.satisfied_by(ex) by {
1900        let s = ex.head();
1901
1902        if lhs.satisfied_by(ex) {
1903            let a = choose|a| #[trigger] a_to_state_pred(a).apply(s);
1904            assert(StatePred::absorb(a_to_state_pred, state_pred)(a).apply(s));
1905        }
1906        if rhs.satisfied_by(ex) {
1907            let a = choose|a| #[trigger] StatePred::absorb(a_to_state_pred, state_pred)(a).apply(s);
1908        }
1909    }
1910    temp_pred_equality(lhs, rhs);
1911}
1912
1913pub broadcast proof fn lift_state_forall_absorb_equality<T, A>(
1914    a_to_state_pred: spec_fn(A) -> StatePred<T>,
1915    state_pred: StatePred<T>,
1916)
1917    requires
1918        ISet::<A>::full() != ISet::<A>::empty(),
1919    ensures
1920        #[trigger] lift_state_forall(a_to_state_pred).and(lift_state(state_pred))
1921            == lift_state_forall(StatePred::absorb(a_to_state_pred, state_pred)),
1922{
1923    broadcast use group_definition_basics;
1924
1925    let lhs = lift_state_forall(a_to_state_pred).and(lift_state(state_pred));
1926    let rhs = lift_state_forall(StatePred::absorb(a_to_state_pred, state_pred));
1927
1928    assert forall|ex| lhs.satisfied_by(ex) == rhs.satisfied_by(ex) by {
1929        let s = ex.head();
1930
1931        if lhs.satisfied_by(ex) {
1932            assert forall|a| #[trigger]
1933                StatePred::absorb(a_to_state_pred, state_pred)(a).apply(s) by {}
1934        }
1935        if rhs.satisfied_by(ex) {
1936            let a = choose|a| ISet::<A>::full().contains(a);
1937            assert(StatePred::absorb(a_to_state_pred, state_pred)(a).apply(s));
1938            assert forall|a| #[trigger] a_to_state_pred(a).apply(s) by {
1939                assert(StatePred::absorb(a_to_state_pred, state_pred)(a).apply(s));
1940            }
1941        }
1942    }
1943    temp_pred_equality(lhs, rhs);
1944}
1945
1946/// Prove `lift_state_exists` leads to by case analysis on another `StatePred`.
1947///
1948/// ## Preconditions
1949/// - `spec ⊧ lift_state_exists(absorb(a_to_temp_pred, p)) ⇝ q`
1950/// - `spec ⊧ lift_state_exists(absorb(a_to_temp_pred, ~p)) ⇝ q`
1951/// ## Postconditions
1952/// - `spec ⊧ lift_state_exists(a_to_temp_pred) ⇝ q`
1953pub proof fn lift_state_exists_leads_to_case_analysis<T, A>(
1954    spec: TempPred<T>,
1955    a_to_temp_pred: spec_fn(A) -> StatePred<T>,
1956    p: StatePred<T>,
1957    q: TempPred<T>,
1958)
1959    requires
1960        spec.entails(lift_state_exists(StatePred::absorb(a_to_temp_pred, p)).leads_to(q)),
1961        spec.entails(lift_state_exists(StatePred::absorb(a_to_temp_pred, p.not())).leads_to(q)),
1962    ensures
1963        spec.entails(lift_state_exists(a_to_temp_pred).leads_to(q)),
1964{
1965    broadcast use {lift_state_exists_absorb_equality, group_definition_basics};
1966
1967    or_leads_to_case_analysis(spec, lift_state_exists(a_to_temp_pred), lift_state(p), q);
1968}
1969
1970/// Leads to `□tla_forall(a_to_temp_pred)` if forall `a`, it leads to `□a_to_temp_pred(a)`.
1971///
1972/// ## Preconditions
1973/// - `forall |a: A|, spec ⊧ p ⇝ □a_to_temp_pred(a)`
1974/// - `forall |a: A|, a \in domain`
1975/// - `domain.is_finite() && domain.len() > 0`
1976/// ## Postconditions
1977/// - `spec ⊧ □tla_forall(a_to_temp_pred)`
1978///
1979/// The domain set assist in showing type A contains finite elements.
1980//
1981// This lemma is actually similar to leads_to_always_combine_n when the n predicates are all a_to_temp_pred(a) for some a.
1982// This is because tla_forall(a_to_temp_pred) == a_to_temp_pred(a1).and(a_to_temp_pred(a2))....and(a_to_temp_pred(an)), We only consider the case when
1983// type A is finite here.
1984pub proof fn leads_to_always_tla_forall<T, A>(
1985    spec: TempPred<T>,
1986    p: TempPred<T>,
1987    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
1988    domain: Set<A>,
1989)
1990    requires
1991        forall|a: A| spec.entails(p.leads_to(always(#[trigger] a_to_temp_pred(a)))),
1992        domain.len() > 0,
1993        forall|a: A| #[trigger] domain.contains(a),
1994    ensures
1995        spec.entails(p.leads_to(always(tla_forall(a_to_temp_pred)))),
1996{
1997    broadcast use {always_unfold, always_propagate_forwards, group_definition_basics};
1998
1999    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(
2000        always(tla_forall(a_to_temp_pred)),
2001    ).satisfied_by(ex) by {
2002        assert forall|i| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(
2003            always(tla_forall(a_to_temp_pred)),
2004        ).satisfied_by(ex.suffix(i)) by {
2005            assert forall|a: A|
2006                p.leads_to(always(#[trigger] a_to_temp_pred(a))).satisfied_by(ex) by {
2007                implies_apply::<T>(ex, spec, p.leads_to(always(a_to_temp_pred(a))));
2008            }
2009            assert forall|a: A|
2010                eventually(always(#[trigger] a_to_temp_pred(a))).satisfied_by(ex.suffix(i)) by {
2011                implies_apply::<T>(ex.suffix(i), p, eventually(always(a_to_temp_pred(a))));
2012            }
2013
2014            let a_to_witness = Map::new(
2015                domain,
2016                |a: A|
2017                    {
2018                        let wit = eventually_choose_witness::<T>(
2019                            ex.suffix(i),
2020                            always(a_to_temp_pred(a)),
2021                        );
2022                        wit
2023                    },
2024            );
2025            assert(a_to_witness.dom() == domain);
2026            let r = |a1: nat, a2: nat| a1 <= a2;
2027            let values = a_to_witness.values();
2028            assert_by(
2029                values.len() > 0,
2030                {
2031                    let x = a_to_witness.dom().choose();
2032                    assert(values.contains(a_to_witness[x]));
2033                },
2034            );
2035            let max_witness = values.find_unique_maximal(r);
2036            values.find_unique_maximal_ensures(r);
2037            values.lemma_maximal_equivalent_greatest(r, max_witness);
2038
2039            assert forall|a: A|
2040                always(#[trigger] a_to_temp_pred(a)).satisfied_by(
2041                    ex.suffix(i).suffix(max_witness),
2042                ) by {
2043                let witness = a_to_witness[a];
2044                assert(values.contains(witness));
2045                assert(r(witness, max_witness));
2046                assert(ex.suffix(i).suffix(max_witness) == ex.suffix(i).suffix(witness).suffix(
2047                    (max_witness - witness) as nat,
2048                ));
2049            }
2050            eventually_proved_by_witness(
2051                ex.suffix(i),
2052                always(tla_forall(a_to_temp_pred)),
2053                max_witness,
2054            );
2055        };
2056    };
2057}
2058
2059// Rules about stability.
2060/// An `□` predicate is `stable`.
2061///
2062/// ## Postconditions
2063/// - `⊧ stable(□p)`
2064pub broadcast proof fn always_p_is_stable<T>(p: TempPred<T>)
2065    ensures
2066        #[trigger] valid(stable(always(p))),
2067{
2068    broadcast use {always_unfold, always_propagate_forwards};
2069
2070}
2071
2072/// A `⇝` predicate is stable.
2073///
2074/// ## Postconditions
2075/// - `⊧ stable(p ⇝ q)`
2076pub proof fn p_leads_to_q_is_stable<T>(p: TempPred<T>, q: TempPred<T>)
2077    ensures
2078        valid(stable(p.leads_to(q))),
2079{
2080    always_p_is_stable(p.implies(eventually(q)));
2081}
2082
2083/// `p ∧ q` is stable if both `p` and `q` are stable.
2084///
2085/// ## Preconditions
2086/// - `⊧ stable(p)`
2087/// - `⊧ stable(q)`
2088/// ## Postconditions
2089/// - `⊧ stable(p ∧ q)`
2090pub broadcast proof fn stable_and_temp<T>(p: TempPred<T>, q: TempPred<T>)
2091    requires
2092        valid(stable(p)),
2093        valid(stable(q)),
2094    ensures
2095        #[trigger] valid(stable(p.and(q))),
2096{
2097    assert forall|ex| #[trigger] p.and(q).satisfied_by(ex) implies always(p.and(q)).satisfied_by(
2098        ex,
2099    ) by {
2100        stable_unfold::<T>(ex, p);
2101        stable_unfold::<T>(ex, q);
2102    }
2103}
2104
2105/// `forall a ⇝ p -> q(a)` is stable.
2106///
2107/// ## Preconditions
2108/// - `∀ a. ⊧ stable(p -> q(a))`
2109///
2110/// ## Postconditions
2111/// - `⊧ stable(∀ a. p -> q(a)))`
2112pub proof fn tla_forall_a_p_leads_to_q_a_is_stable<T, A>(
2113    p: TempPred<T>,
2114    a_to_temp_pred: spec_fn(A) -> TempPred<T>,
2115)
2116    requires
2117        forall|a: A| #[trigger] valid(stable(p.leads_to(a_to_temp_pred(a)))),
2118    ensures
2119        valid(stable(tla_forall(|a: A| p.leads_to(a_to_temp_pred(a))))),
2120{
2121    broadcast use group_definition_basics;
2122
2123    let target = tla_forall(|a: A| p.leads_to(a_to_temp_pred(a)));
2124    assert forall|ex|
2125        (forall|a: A| #[trigger]
2126            valid(stable(p.leads_to(a_to_temp_pred(a))))) implies #[trigger] stable(
2127        target,
2128    ).satisfied_by(ex) by {
2129        assert forall|i|
2130            (forall|a: A| #[trigger] valid(stable(p.leads_to(a_to_temp_pred(a)))))
2131                && target.satisfied_by(ex) implies #[trigger] target.satisfied_by(ex.suffix(i)) by {
2132            assert forall|a: A|
2133                p.leads_to(a_to_temp_pred(a)).satisfied_by(ex) implies #[trigger] p.leads_to(
2134                a_to_temp_pred(a),
2135            ).satisfied_by(ex.suffix(i)) by {
2136                assert(valid(stable(p.leads_to(a_to_temp_pred(a)))));
2137                assert(stable(p.leads_to(a_to_temp_pred(a))).satisfied_by(ex));
2138                if p.leads_to(a_to_temp_pred(a)).satisfied_by(ex) {
2139                }
2140            }
2141        }
2142    }
2143}
2144
2145/// Unpack the conditions from the left to the right side of `⊧`
2146///
2147/// ## Preconditions
2148/// - `⊧ stable(spec)`
2149/// - `spec ∧ c ⊧ p ⇝ q`
2150/// ## Postconditions
2151/// - `spec ⊧ p ∧ c ⇝ q`
2152pub proof fn unpack_conditions_from_spec<T>(
2153    spec: TempPred<T>,
2154    c: TempPred<T>,
2155    p: TempPred<T>,
2156    q: TempPred<T>,
2157)
2158    requires
2159        valid(stable(spec)),
2160        spec.and(c).entails(p.leads_to(q)),
2161    ensures
2162        spec.entails(p.and(c).leads_to(q)),
2163{
2164    broadcast use {always_unfold, implies_apply, group_definition_basics};
2165
2166    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.and(c).leads_to(q).satisfied_by(
2167        ex,
2168    ) by {
2169        assert forall|i| #[trigger] p.and(c).satisfied_by(ex.suffix(i)) implies eventually(
2170            q,
2171        ).satisfied_by(ex.suffix(i)) by {
2172            stable_unfold::<T>(ex, spec);
2173            implies_apply::<T>(ex.suffix(i), spec.and(c), p.leads_to(q));
2174            assert(ex.suffix(i) == ex.suffix(i).suffix(0));
2175            implies_apply::<T>(ex.suffix(i), p, eventually(q));
2176        };
2177    };
2178}
2179
2180/// Pack the conditions from the right to the left side of `⊧`.
2181///
2182/// ## Preconditions
2183/// - `spec ⊧ p ∧ c ⇝ q`
2184///
2185/// ## Postconditions
2186/// - `spec ∧ □c ⊧ p ⇝ q`
2187pub proof fn pack_conditions_to_spec<T>(
2188    spec: TempPred<T>,
2189    c: TempPred<T>,
2190    p: TempPred<T>,
2191    q: TempPred<T>,
2192)
2193    requires
2194        spec.entails(p.and(c).leads_to(q)),
2195    ensures
2196        spec.and(always(c)).entails(p.leads_to(q)),
2197{
2198    broadcast use {always_unfold, always_propagate_forwards};
2199
2200    assert forall|ex| #[trigger] spec.and(always(c)).satisfied_by(ex) implies p.leads_to(
2201        q,
2202    ).satisfied_by(ex) by {
2203        implies_apply(ex, spec, p.and(c).leads_to(q));
2204        leads_to_unfold(ex, p.and(c), q);
2205
2206    }
2207}
2208
2209/// Make the predicate as concise as possible.
2210///
2211/// Similar to the first-order logic where `p` equals `p ∧ q` when `p -> q` is satisfied,
2212/// we can reduce the size of predicate when some part of it implies the rest.
2213///
2214/// ## Preconditions
2215/// - `p ⊧ q`
2216/// ## Postconditions
2217/// - `p == p ∧ q`
2218// Used to be named as simplify_predicate.
2219pub proof fn entails_and_equality<T>(p: TempPred<T>, q: TempPred<T>)
2220    requires
2221        p.entails(q),
2222    ensures
2223        p == p.and(q),
2224{
2225    assert forall|ex| #[trigger] p.satisfied_by(ex) implies p.and(q).satisfied_by(ex) by {
2226        entails_and_temp::<T>(p, p, q);
2227        entails_apply::<T>(ex, p, p.and(q));
2228    };
2229    temp_pred_equality::<T>(p, p.and(q));
2230}
2231
2232/// Transitivity of `⊧` with simplification.
2233///
2234/// ## Preconditions
2235/// - `spec ⊧ p`
2236/// - `spec ∧ p ⊧ q`
2237/// ## Postconditions
2238/// - `spec ⊧ q`
2239pub proof fn entails_trans_by_simplify<T>(spec: TempPred<T>, p: TempPred<T>, q: TempPred<T>)
2240    requires
2241        spec.entails(p),
2242        spec.and(p).entails(q),
2243    ensures
2244        spec.entails(q),
2245{
2246    entails_and_equality(spec, p);
2247}
2248
2249// More advanced rules.
2250/// Proving `p ⇝ q` by borrowing the inv.
2251///
2252/// ## Preconditions
2253/// - `spec ⊧ p ∧ inv ⇝ q`
2254/// - `spec ⊧ □inv`
2255/// ## Postconditions
2256/// - `spec ⊧ p ⇝ q`
2257pub proof fn leads_to_by_borrowing_inv<T>(
2258    spec: TempPred<T>,
2259    p: TempPred<T>,
2260    q: TempPred<T>,
2261    inv: TempPred<T>,
2262)
2263    requires
2264        spec.entails(p.and(inv).leads_to(q)),
2265        spec.entails(always(inv)),
2266    ensures
2267        spec.entails(p.leads_to(q)),
2268{
2269    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(q).satisfied_by(ex) by {
2270        assert forall|i| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(q).satisfied_by(
2271            ex.suffix(i),
2272        ) by {
2273            instantiate_entailed_always(ex, i, spec, inv);
2274            instantiate_entailed_leads_to(ex, i, spec, p.and(inv), q);
2275        }
2276    }
2277}
2278
2279/// Enhance the conclusion of leads-to □ using invariant.
2280///
2281/// ## Preconditions
2282/// - `spec ⊧ □inv`
2283/// - `spec ⊧ p ⇝ □q1`
2284/// - `q1 ∧ inv ⊧ q2`
2285/// ## Postconditions
2286/// - `spec ⊧ p ⇝ □q2`
2287pub proof fn leads_to_always_enhance<T>(
2288    spec: TempPred<T>,
2289    inv: TempPred<T>,
2290    p: TempPred<T>,
2291    q1: TempPred<T>,
2292    q2: TempPred<T>,
2293)
2294    requires
2295        spec.entails(always(inv)),
2296        spec.entails(p.leads_to(always(q1))),
2297        q1.and(inv).entails(q2),
2298    ensures
2299        spec.entails(p.leads_to(always(q2))),
2300{
2301    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(always(q2)).satisfied_by(
2302        ex,
2303    ) by {
2304        assert forall|i| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(
2305            always(q2),
2306        ).satisfied_by(ex.suffix(i)) by {
2307            implies_apply(ex, spec, always(inv));
2308            implies_apply(ex, spec, p.leads_to(always(q1)));
2309            leads_to_unfold(ex, p, always(q1));
2310            implies_apply(ex.suffix(i), p, eventually(always(q1)));
2311            let witness = eventually_choose_witness(ex.suffix(i), always(q1));
2312            assert forall|j| #[trigger] q2.satisfied_by(ex.suffix(i).suffix(witness).suffix(j)) by {
2313                assert(ex.suffix(i).suffix(witness).suffix(j) == ex.suffix(i + witness + j));
2314                implies_apply(ex.suffix(i).suffix(witness).suffix(j), q1.and(inv), q2);
2315            }
2316            eventually_proved_by_witness(ex.suffix(i), always(q2), witness);
2317        }
2318    }
2319}
2320
2321/// Weaken `⇝` by `⇒`.
2322///
2323/// ## Preconditions
2324/// - `spec ⊧ □(p2 ⇒ p1)`
2325/// - `spec ⊧ □(q1 ⇒ q2)`
2326/// - `spec ⊧ p1 ⇝ q1`
2327/// ## Postconditions
2328/// - `spec ⊧ p2 ⇝ q2`
2329pub proof fn leads_to_weaken<T>(
2330    spec: TempPred<T>,
2331    p1: TempPred<T>,
2332    q1: TempPred<T>,
2333    p2: TempPred<T>,
2334    q2: TempPred<T>,
2335)
2336    requires
2337        spec.entails(always(p2.implies(p1))),
2338        spec.entails(always(q1.implies(q2))),
2339        spec.entails(p1.leads_to(q1)),
2340    ensures
2341        spec.entails(p2.leads_to(q2)),
2342{
2343    always_implies_to_leads_to::<T>(spec, p2, p1);
2344    always_implies_to_leads_to::<T>(spec, q1, q2);
2345    leads_to_trans::<T>(spec, p2, p1, q1);
2346    leads_to_trans::<T>(spec, p2, q1, q2);
2347}
2348
2349/// Proving `p ⇝ q` vacuously.
2350///
2351/// ## Preconditions
2352/// - `spec ⊧ □r`
2353/// - `p ∧ r == false`
2354/// ## Postconditions
2355/// - `spec ⊧ p ⇝ q`
2356pub proof fn vacuous_leads_to<T>(spec: TempPred<T>, p: TempPred<T>, q: TempPred<T>, r: TempPred<T>)
2357    requires
2358        spec.entails(always(r)),
2359        p.and(r) == false_pred::<T>(),
2360    ensures
2361        spec.entails(p.leads_to(q)),
2362{
2363    broadcast use {always_unfold, implies_apply, group_execution_suffix_lemmas};
2364
2365    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(q).satisfied_by(ex) by {
2366        assert forall|i| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(q).satisfied_by(
2367            ex.suffix(i),
2368        ) by {
2369            assert_by(
2370                !p.satisfied_by(ex.suffix(i)),
2371                {
2372                    implies_apply::<T>(ex, spec, always(r));
2373                    if p.satisfied_by(ex.suffix(i)) {
2374                        assert(p.and(r).satisfied_by(ex.suffix(i)));
2375                    }
2376                },
2377            );
2378        }
2379    }
2380}
2381
2382/// Derive `p ⇝ q` from `□p ⇝ q` with the assumption that `p` is preserved unless `q` happens.
2383///
2384/// This lemma is useful if we want to show that given `□p ⇝ q`, `q` will eventually hold
2385/// even if `□p` doesn't hold, as long as `p` is preserved until `q` happens.
2386/// A concrete usage is to reason about a pair of concurrent components A and B, where
2387/// (1) A guarantees `□p ⇝ q`, and (2) B makes `p` hold at some point and keeps `p` until `q` holds.
2388/// Note that we formalize "p is preserved until q happens" using `□(p ∧ next ⇒ p' ∨ q')`:
2389/// if `p` holds now, then for any possible next state, either `p` or `q` holds.
2390///
2391/// ## Preconditions
2392/// - `spec ⊧ □p ⇝ q`
2393/// - `spec ⊧ □(p ∧ next ⇒ p' ∨ q')`
2394/// - `spec ⊧ □next`
2395/// ## Postconditions
2396///  - `spec ⊧ p ⇝ q`
2397pub proof fn strengthen_leads_to_with_until<T>(
2398    spec: TempPred<T>,
2399    next: TempPred<T>,
2400    p: TempPred<T>,
2401    q: TempPred<T>,
2402)
2403    requires
2404        spec.entails(always(p).leads_to(q)),
2405        spec.entails(always(p.and(next).implies(later(p).or(later(q))))),
2406        spec.entails(always(next)),
2407    ensures
2408        spec.entails(p.leads_to(q)),
2409{
2410    broadcast use {
2411        always_unfold,
2412        implies_apply,
2413        group_execution_suffix_lemmas,
2414        group_definition_basics,
2415    };
2416
2417    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(q).satisfied_by(ex) by {
2418        implies_apply(ex, spec, always(next));
2419        implies_apply(ex, spec, always(p.and(next).implies(later(p).or(later(q)))));
2420        always_p_or_eventually_q(ex, next, p, q);
2421        assert forall|i| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(q).satisfied_by(
2422            ex.suffix(i),
2423        ) by {
2424            if always(p).satisfied_by(ex.suffix(i)) {
2425                implies_apply(ex, spec, always(p).leads_to(q));
2426            }
2427        }
2428    }
2429}
2430
2431/// Get a new `⇝` condition with an until condition.
2432///
2433/// This lemma can be used in compositional proof.
2434/// Suppose that a system consists of two concurrent components `A` and `B`,
2435/// and we want to prove that the entire system makes `P1 ⇝ P3`.
2436/// If we have already proved that
2437/// (1) `A` makes `P1 ⇝ P2` hold, and
2438/// (2) `P2` holds until `P3` holds, and
2439/// (3) if `P2` holds until `P3` holds, then `B` makes `P2 ⇝ P3`
2440/// (in other words, `B` requires that `P2` should hold until `B` makes `P3` hold),
2441/// then we can apply this lemma and prove that the entire system makes `P2 ⇝ P3`,
2442/// then by transitivity we have `P1 ⇝ P3`.
2443///
2444/// Such a case could happen between components with liveness dependencies:
2445/// `A` at some point needs to delegate the task to `B` and `A` needs to wait until `B` finish
2446/// so `A` can start the next task, meanwhile when `B` is working `A` should not disable `B`'s
2447/// progress (i.e., `A` should make sure `P2` holds until `P3` holds).
2448///
2449/// ## Preconditions
2450/// - `spec ⊧ p1 ⇝ q1`
2451/// - `spec ⊧ □(p2 ∧ next ⇒ p2' ∨ q2')`
2452/// - `spec ⊧ □next`
2453/// ## Postconditions
2454/// - `spec ⊧ p1 ∧ p2 ⇝ (q1 ∧ p2) ∨ q2`
2455pub proof fn transform_leads_to_with_until<T>(
2456    spec: TempPred<T>,
2457    next: TempPred<T>,
2458    p1: TempPred<T>,
2459    q1: TempPred<T>,
2460    p2: TempPred<T>,
2461    q2: TempPred<T>,
2462)
2463    requires
2464        spec.entails(p1.leads_to(q1)),
2465        spec.entails(always(p2.and(next).implies(later(p2).or(later(q2))))),
2466        spec.entails(always(next)),
2467    ensures
2468        spec.entails(p1.and(p2).leads_to((q1.and(p2)).or(q2))),
2469{
2470    broadcast use {
2471        always_unfold,
2472        implies_apply,
2473        group_execution_suffix_lemmas,
2474        group_definition_basics,
2475    };
2476
2477    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p1.and(p2).leads_to(
2478        (q1.and(p2)).or(q2),
2479    ).satisfied_by(ex) by {
2480        assert forall|i| #[trigger] p1.and(p2).satisfied_by(ex.suffix(i)) implies eventually(
2481            (q1.and(p2)).or(q2),
2482        ).satisfied_by(ex.suffix(i)) by {
2483            implies_apply::<T>(ex, spec, always(next));
2484            implies_apply::<T>(ex, spec, always(p2.and(next).implies(later(p2).or(later(q2)))));
2485
2486            always_p_or_eventually_q::<T>(ex, next, p2, q2);
2487
2488            implies_apply::<T>(ex, spec, p1.leads_to(q1));
2489
2490            if eventually(q2).satisfied_by(ex.suffix(i)) {
2491                let witness_idx = eventually_choose_witness::<T>(ex.suffix(i), q2);
2492                eventually_proved_by_witness::<T>(ex.suffix(i), (q1.and(p2)).or(q2), witness_idx);
2493            } else {
2494                let witness_idx = eventually_choose_witness::<T>(ex.suffix(i), q1);
2495                eventually_proved_by_witness::<T>(ex.suffix(i), (q1.and(p2)).or(q2), witness_idx);
2496            }
2497        }
2498    }
2499}
2500
2501/// Concluding `p(n) ⇝ p(0)` using ranking functions, with a step of one.
2502///
2503/// ## Preconditions
2504/// - `forall |n: nat|, n > 0 ==> spec ⊧ p(n) ⇝ p(n - 1)`
2505/// ## Postconditions
2506///  - `forall |n: nat|, spec ⊧ p(n) ⇝ p(0)`
2507pub proof fn leads_to_rank_step_one<T>(spec: TempPred<T>, p: spec_fn(nat) -> TempPred<T>)
2508    requires
2509        forall|n: nat| #![trigger p(n)] (n > 0 ==> spec.entails(p(n).leads_to(p((n - 1) as nat)))),
2510    ensures
2511        forall|n: nat| #[trigger] spec.entails(p(n).leads_to(p(0))),
2512{
2513    let pre = {
2514        forall|n: nat| #![trigger p(n)] (n > 0 ==> spec.entails(p(n).leads_to(p((n - 1) as nat))))
2515    };
2516    assert forall|n: nat| pre implies #[trigger] spec.entails(p(n).leads_to(p(0))) by {
2517        leads_to_rank_step_one_help(spec, p, n);
2518    }
2519}
2520
2521proof fn leads_to_rank_step_one_help<T>(spec: TempPred<T>, p: spec_fn(nat) -> TempPred<T>, n: nat)
2522    requires
2523        forall|n: nat| #![trigger p(n)] (n > 0 ==> spec.entails(p(n).leads_to(p((n - 1) as nat)))),
2524    ensures
2525        spec.entails(p(n).leads_to(p(0))),
2526    decreases n,
2527{
2528    if n > 0 {
2529        // p(n) ⇝ p(n - 1), p(n - 1) ⇝ p(0)
2530        // combine with leads-to transitivity
2531        leads_to_rank_step_one_help(spec, p, (n - 1) as nat);
2532        leads_to_trans_n!(spec, p(n), p((n - 1) as nat), p(0));
2533    } else {
2534        // p(0) ⇝ p(0) trivially
2535        leads_to_self_temp(p(0));
2536    }
2537}
2538
2539/// `usize` version of the proof rule [leads_to_rank_step_one].
2540pub proof fn leads_to_rank_step_one_usize<T>(spec: TempPred<T>, p: spec_fn(usize) -> TempPred<T>)
2541    requires
2542        forall|n: usize|
2543            #![trigger p(n)]
2544            (n > 0 ==> spec.entails(p(n).leads_to(p((n - 1) as usize)))),
2545    ensures
2546        forall|n: usize| #[trigger] spec.entails(p(n).leads_to(p(0))),
2547{
2548    let pre = {
2549        forall|n: usize|
2550            #![trigger p(n)]
2551            (n > 0 ==> spec.entails(p(n).leads_to(p((n - 1) as usize))))
2552    };
2553    assert forall|n: usize| pre implies #[trigger] spec.entails(p(n).leads_to(p(0))) by {
2554        leads_to_rank_step_one_usize_help(spec, p, n);
2555    }
2556}
2557
2558proof fn leads_to_rank_step_one_usize_help<T>(
2559    spec: TempPred<T>,
2560    p: spec_fn(usize) -> TempPred<T>,
2561    n: usize,
2562)
2563    requires
2564        forall|n: usize|
2565            #![trigger p(n)]
2566            (n > 0 ==> spec.entails(p(n).leads_to(p((n - 1) as usize)))),
2567    ensures
2568        spec.entails(p(n).leads_to(p(0))),
2569    decreases n,
2570{
2571    if n > 0 {
2572        // p(n) ⇝ p(n - 1), p(n - 1) ⇝ p(0)
2573        // combine with leads-to transitivity
2574        leads_to_rank_step_one_usize_help(spec, p, (n - 1) as usize);
2575        leads_to_trans_n!(spec, p(n), p((n - 1) as usize), p(0));
2576    } else {
2577        // p(0) ⇝ p(0) trivially
2578        leads_to_self_temp(p(0));
2579    }
2580}
2581
2582// Rules about state machine transitions.
2583/// Prove safety by induction.
2584///
2585/// ## Preconditions
2586/// - `⊧ init ⇒ inv``
2587/// - `⊧ inv ∧ next ⇒ inv'`
2588/// - `spec ⊧ init ∧ □next`
2589/// ## Postconditions
2590/// - `spec ⊧ □inv`
2591pub proof fn init_invariant<T>(
2592    spec: TempPred<T>,
2593    init: StatePred<T>,
2594    next: ActionPred<T>,
2595    inv: StatePred<T>,
2596)
2597    requires
2598        forall|s: T| #[trigger] init.apply(s) ==> inv.apply(s),
2599        forall|s, s_prime: T|
2600            inv.apply(s) && #[trigger] next.apply(s, s_prime) ==> inv.apply(s_prime),
2601        spec.entails(lift_state(init)),
2602        spec.entails(always(lift_action(next))),
2603    ensures
2604        spec.entails(always(lift_state(inv))),
2605{
2606    broadcast use group_tla_rules;
2607
2608    assert forall|ex: Execution<T>| spec.satisfied_by(ex) implies #[trigger] always(
2609        lift_state(inv),
2610    ).satisfied_by(ex) by {
2611        implies_apply(ex, spec, lift_state(init));
2612        implies_apply(ex, spec, always(lift_action(next)));
2613        assert forall|i: nat| inv.apply(#[trigger] ex.suffix(i).head()) by {
2614            init_invariant_rec(ex, init, next, inv, i);
2615        };
2616    };
2617}
2618
2619/// Implies new invariant from proved invariant by induction.
2620///
2621/// ## Preconditions
2622/// - `⊧ init ⇒ inv`
2623/// - `⊧ inv ∧ proved_inv ∧ next ⇒ inv'`
2624/// - `spec ⊧ init ∧ □next ∧ □proved_inv`
2625/// ## Postconditions
2626/// - `spec ⊧ □inv`
2627pub proof fn implies_new_invariant<T>(
2628    spec: TempPred<T>,
2629    init: StatePred<T>,
2630    next: ActionPred<T>,
2631    inv: StatePred<T>,
2632    proved_inv: StatePred<T>,
2633)
2634    requires
2635        forall|s: T| #[trigger] init.apply(s) ==> inv.apply(s),
2636        forall|s, s_prime: T|
2637            inv.apply(s) && proved_inv.apply(s) && #[trigger] next.apply(s, s_prime) ==> inv.apply(
2638                s_prime,
2639            ),
2640        spec.entails(lift_state(init)),
2641        spec.entails(always(lift_action(next))),
2642        spec.entails(always(lift_state(proved_inv))),
2643    ensures
2644        spec.entails(always(lift_state(inv))),
2645{
2646    broadcast use group_tla_rules;
2647
2648    assert forall|ex: Execution<T>| spec.satisfied_by(ex) implies #[trigger] always(
2649        lift_state(inv),
2650    ).satisfied_by(ex) by {
2651        implies_apply(ex, spec, lift_state(init));
2652        implies_apply(ex, spec, always(lift_action(next)));
2653        implies_apply(ex, spec, always(lift_state(proved_inv)));
2654        assert forall|i: nat| inv.apply(#[trigger] ex.suffix(i).head()) by {
2655            implies_new_invariant_rec(ex, init, next, inv, proved_inv, i);
2656        };
2657    };
2658}
2659
2660/// Get the initial `⇝`.
2661///
2662/// ## Preconditions
2663/// - `spec ⊧ □(p ∧ next ⇒ p' ∨ q')`
2664/// - `spec ⊧ □(p ∧ next ∧ forward ⇒ q')`
2665/// - `spec ⊧ □next`
2666/// - `spec ⊧ □p ⇝ forward`
2667/// ## Postconditions
2668/// - `spec ⊧ p ⇝ q`
2669pub proof fn wf1_variant_temp<T>(
2670    spec: TempPred<T>,
2671    next: TempPred<T>,
2672    forward: TempPred<T>,
2673    p: TempPred<T>,
2674    q: TempPred<T>,
2675)
2676    requires
2677        spec.entails(always(p.and(next).implies(later(p).or(later(q))))),
2678        spec.entails(always(p.and(next).and(forward).implies(later(q)))),
2679        spec.entails(always(next)),
2680        spec.entails(always(p).leads_to(forward)),
2681    ensures
2682        spec.entails(p.leads_to(q)),
2683{
2684    broadcast use group_tla_rules;
2685
2686    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies p.leads_to(q).satisfied_by(ex) by {
2687        assert forall|i| #[trigger] p.satisfied_by(ex.suffix(i)) implies eventually(q).satisfied_by(
2688            ex.suffix(i),
2689        ) by {
2690            implies_apply::<T>(ex, spec, always(next));
2691            implies_apply::<T>(ex, spec, always(p.and(next).implies(later(p).or(later(q)))));
2692            implies_apply::<T>(ex, spec, always(p.and(next).and(forward).implies(later(q))));
2693
2694            always_p_or_eventually_q::<T>(ex, next, p, q);
2695            implies_apply::<T>(ex.suffix(i), p, always(p).or(eventually(q)));
2696            if always(p).satisfied_by(ex.suffix(i)) {
2697                implies_apply::<T>(ex, spec, always(p).leads_to(forward));
2698                leads_to_unfold::<T>(ex, always(p), forward);
2699                implies_apply::<T>(ex.suffix(i), always(p), eventually(forward));
2700                let witness_idx = eventually_choose_witness::<T>(ex.suffix(i), forward);
2701
2702                always_propagate_forwards::<T>(ex, next, i);
2703                always_propagate_forwards::<T>(ex, p.and(next).and(forward).implies(later(q)), i);
2704                implies_apply::<T>(
2705                    ex.suffix(i).suffix(witness_idx),
2706                    p.and(next).and(forward),
2707                    later(q),
2708                );
2709                assert(ex.suffix(i).suffix(witness_idx).suffix(1) == ex.suffix(i).suffix(
2710                    witness_idx + 1,
2711                ));
2712                eventually_proved_by_witness::<T>(ex.suffix(i), q, witness_idx + 1);
2713            }
2714        }
2715    }
2716}
2717
2718/// Get the initial `⇝` with a stronger wf assumption than [`wf1_variant_temp`].
2719///
2720/// ## Preconditions
2721/// - `⊧ p ∧ next ⇒ p' ∨ q'`
2722/// - `⊧ p ∧ next ∧ forward ⇒ q'`
2723/// - `⊧ p ⇒ enabled(forward)`
2724/// - `spec ⊧ □lift_action(next)`
2725/// - `spec ⊧ wf(forward)`
2726/// ## Postconditions
2727/// - `spec ⊧ p ⇝ q`
2728pub proof fn wf1<T>(
2729    spec: TempPred<T>,
2730    next: ActionPred<T>,
2731    forward: ActionPred<T>,
2732    p: StatePred<T>,
2733    q: StatePred<T>,
2734)
2735    requires
2736        forall|s, s_prime: T|
2737            p.apply(s) && #[trigger] next.apply(s, s_prime) ==> p.apply(s_prime) || q.apply(
2738                s_prime,
2739            ),
2740        forall|s, s_prime: T|
2741            p.apply(s) && #[trigger] next.apply(s, s_prime) && forward.apply(s, s_prime)
2742                ==> q.apply(s_prime),
2743        forall|s: T| #[trigger] p.apply(s) ==> enabled(forward).apply(s),
2744        spec.entails(always(lift_action(next))),
2745        spec.entails(weak_fairness(forward)),
2746    ensures
2747        spec.entails(lift_state(p).leads_to(lift_state(q))),
2748{
2749    broadcast use group_tla_rules;
2750
2751    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies always(lift_state(p)).leads_to(
2752        lift_action(forward),
2753    ).satisfied_by(ex) by {
2754        assert forall|i| #[trigger]
2755            always(lift_state(p)).satisfied_by(ex.suffix(i)) implies eventually(
2756            lift_action(forward),
2757        ).satisfied_by(ex.suffix(i)) by {
2758            implies_apply_with_always::<T>(
2759                ex.suffix(i),
2760                lift_state(p),
2761                lift_state(enabled(forward)),
2762            );
2763            assert(ex.suffix(i).suffix(0) == ex.suffix(i));
2764
2765            implies_apply::<T>(ex, spec, weak_fairness(forward));
2766            weak_fairness_unfold::<T>(ex, forward);
2767            implies_apply::<T>(
2768                ex.suffix(i),
2769                lift_state(enabled(forward)),
2770                eventually(lift_action(forward)),
2771            );
2772        };
2773    };
2774    wf1_variant_temp::<T>(
2775        spec,
2776        lift_action(next),
2777        lift_action(forward),
2778        lift_state(p),
2779        lift_state(q),
2780    );
2781}
2782
2783/// Get the initial `⇝` with a stronger wf assumption by borrowing existing inv.
2784///
2785/// ## Preconditions
2786/// - `⊧ p ∧ inv ∧ next ⇒ p' ∨ q'`
2787/// - `⊧ p ∧ inv ∧ next ∧ forward ⇒ q'`
2788/// - `⊧ p ∧ inv ⇒ enabled(forward)`
2789/// - `spec ⊧ □lift_action(next)`
2790/// - `spec ⊧ □lift_state(inv)`
2791/// - `spec ⊧ wf(forward)`
2792/// ## Postconditions
2793/// - `spec ⊧ p ⇝ q`
2794pub proof fn wf1_by_borrowing_inv<T>(
2795    spec: TempPred<T>,
2796    next: ActionPred<T>,
2797    forward: ActionPred<T>,
2798    p: StatePred<T>,
2799    q: StatePred<T>,
2800    inv: StatePred<T>,
2801)
2802    requires
2803        forall|s, s_prime: T|
2804            p.apply(s) && inv.apply(s) && #[trigger] next.apply(s, s_prime) ==> p.apply(s_prime)
2805                || q.apply(s_prime),
2806        forall|s, s_prime: T|
2807            p.apply(s) && inv.apply(s) && #[trigger] next.apply(s, s_prime) && forward.apply(
2808                s,
2809                s_prime,
2810            ) ==> q.apply(s_prime),
2811        forall|s: T| #[trigger] p.apply(s) && inv.apply(s) ==> enabled(forward).apply(s),
2812        spec.entails(always(lift_action(next))),
2813        spec.entails(always(lift_state(inv))),
2814        spec.entails(weak_fairness(forward)),
2815    ensures
2816        spec.entails(lift_state(p).leads_to(lift_state(q))),
2817{
2818    broadcast use group_tla_rules;
2819
2820    let next_and_inv = lift_action(next).and(lift_state(inv));
2821
2822    assert forall|ex| #[trigger] spec.satisfied_by(ex) implies always(
2823        lift_state(p).and(lift_state(inv)),
2824    ).leads_to(lift_action(forward)).satisfied_by(ex) by {
2825        assert forall|i| #[trigger]
2826            always(lift_state(p).and(lift_state(inv))).satisfied_by(
2827                ex.suffix(i),
2828            ) implies eventually(lift_action(forward)).satisfied_by(ex.suffix(i)) by {
2829            implies_apply_with_always::<T>(
2830                ex.suffix(i),
2831                lift_state(p).and(lift_state(inv)),
2832                lift_state(enabled(forward)),
2833            );
2834            assert(ex.suffix(i).suffix(0) == ex.suffix(i));
2835            implies_apply::<T>(ex, spec, weak_fairness(forward));
2836            weak_fairness_unfold::<T>(ex, forward);
2837            implies_apply::<T>(
2838                ex.suffix(i),
2839                lift_state(enabled(forward)),
2840                eventually(lift_action(forward)),
2841            );
2842        };
2843    };
2844    entails_always_and_n!(spec, lift_action(next), lift_state(inv));
2845    always_and_equality(lift_state(p), lift_state(inv));
2846    always_double_equality(lift_state(inv));
2847    leads_to_by_borrowing_inv(
2848        spec,
2849        always(lift_state(p)),
2850        lift_action(forward),
2851        always(lift_state(inv)),
2852    );
2853    wf1_variant_temp::<T>(spec, next_and_inv, lift_action(forward), lift_state(p), lift_state(q));
2854}
2855
2856/// Strengthen next with inv.
2857///
2858/// ## Preconditions
2859/// - `spec ⊧ □next`
2860/// - `spec ⊧ □inv`
2861/// - `⊧ next ∧ inv <=> next_and_inv`
2862/// ## Postconditions
2863/// - `spec ⊧ □next_and_inv`
2864pub proof fn strengthen_next<T>(
2865    spec: TempPred<T>,
2866    next: ActionPred<T>,
2867    inv: StatePred<T>,
2868    next_and_inv: ActionPred<T>,
2869)
2870    requires
2871        spec.entails(always(lift_action(next))),
2872        spec.entails(always(lift_state(inv))),
2873        lift_action(next_and_inv).entails(lift_action(next).and(lift_state(inv))),
2874        lift_action(next).and(lift_state(inv)).entails(lift_action(next_and_inv)),
2875    ensures
2876        spec.entails(always(lift_action(next_and_inv))),
2877{
2878    entails_and_temp::<T>(spec, always(lift_action(next)), always(lift_state(inv)));
2879    always_and_equality::<T>(lift_action(next), lift_state(inv));
2880    temp_pred_equality::<T>(lift_action(next_and_inv), lift_action(next).and(lift_state(inv)));
2881}
2882
2883// Macros for multiple-predicate variants of the above rules.
2884#[macro_export]
2885macro_rules! leads_to_trans_n {
2886    [$($tail:tt)*] => {
2887        ::vstd::prelude::verus_proof_macro_exprs!($crate::temporal_logic::rules::leads_to_trans_n_internal!($($tail)*));
2888    };
2889}
2890
2891#[macro_export]
2892macro_rules! leads_to_trans_n_internal {
2893    ($spec:expr, $p1:expr, $p2:expr, $p3:expr $(,)?) => {
2894        leads_to_trans($spec, $p1, $p2, $p3);
2895    };
2896    ($spec:expr, $p1:expr, $p2:expr, $p3:expr, $($tail:tt)*) => {
2897        leads_to_trans($spec, $p1, $p2, $p3);
2898        leads_to_trans_n_internal!($spec, $p1, $p3, $($tail)*);
2899    };
2900}
2901
2902pub use leads_to_trans_n;
2903pub use leads_to_trans_n_internal;
2904
2905// Combine multiple StatePred using `.and`.
2906// Usage: state_pred_and!(p1) | p1
2907//        state_pred_and!(p1, p2) | p1.and(p2)
2908//        state_pred_and!(p1, p2, p3, ...) | p1.and(p2).and(p3)...
2909#[macro_export]
2910macro_rules! state_pred_and {
2911    ($p1:expr $(,)?) => {
2912        $p1
2913    };
2914    ($p1:expr, $p2:expr $(,)?) => {
2915        $p1.and($p2)
2916    };
2917    ($p1:expr, $p2:expr, $($tail:expr),+ $(,)?) => {
2918        {
2919            let tmp = $p1.and($p2);
2920            $( let tmp = tmp.and($tail); )*
2921            tmp
2922        }
2923    };
2924}
2925
2926pub use state_pred_and;
2927
2928// Combine multiple TempPred using `.and`.
2929// Usage: temp_pred_and!(p1) | p1
2930//        temp_pred_and!(p1, p2) | p1.and(p2)
2931//        temp_pred_and!(p1, p2, p3, ...) | p1.and(p2).and(p3)...
2932#[macro_export]
2933macro_rules! temp_pred_and {
2934    [$($tail:tt)*] => {
2935        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::temp_pred_and_internal!($($tail)*))
2936    }
2937}
2938
2939#[macro_export]
2940macro_rules! temp_pred_and_internal {
2941    ($next:expr) => {
2942        $next
2943    };
2944    ($next:expr, $($expr:expr),* $(,)?) => {
2945        $next $(
2946            .and($expr)
2947        )*
2948    };
2949}
2950
2951pub use temp_pred_and;
2952pub use temp_pred_and_internal;
2953
2954// Entails the conjunction of all the p if entails each of them.
2955// ## Preconditions
2956//     spec ⊧ p1
2957//     spec ⊧ p2
2958//        ...
2959//     spec ⊧ pn
2960// ## Postconditions
2961//     spec ⊧ p1 ∧ p2 ∧ ... ∧ pn
2962//
2963// Usage: entails_and_n!(spec, p1, p2, p3, p4)
2964#[macro_export]
2965macro_rules! entails_and_n {
2966    [$($tail:tt)*] => {
2967        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::entails_and_n_internal!($($tail)*));
2968    };
2969}
2970
2971#[macro_export]
2972macro_rules! entails_and_n_internal {
2973    ($spec:expr, $p1:expr, $p2:expr $(,)?) => {
2974        entails_and_temp($spec, $p1, $p2);
2975    };
2976    ($spec:expr, $p1:expr, $p2:expr, $($tail:tt)*) => {
2977        entails_and_temp($spec, $p1, $p2);
2978        entails_and_n_internal!($spec, $p1.and($p2), $($tail)*);
2979    };
2980}
2981
2982pub use entails_and_n;
2983pub use entails_and_n_internal;
2984
2985// Entails □ the conjunction of all the p if entails each always p.
2986// ## Preconditions
2987//     spec ⊧ □p1
2988//     spec ⊧ □p2
2989//        ...
2990//     spec ⊧ □pn
2991// ## Postconditions
2992//     spec ⊧ □(p1 ∧ p2 ∧ ... ∧ pn)
2993//
2994// Usage: entails_always_and_n!(spec, p1, p2, p3, p4)
2995#[macro_export]
2996macro_rules! entails_always_and_n {
2997    [$($tail:tt)*] => {
2998        ::vstd::prelude::verus_proof_macro_exprs!($crate::temporal_logic::rules::entails_always_and_n_internal!($($tail)*));
2999    };
3000}
3001
3002#[macro_export]
3003macro_rules! entails_always_and_n_internal {
3004    ($spec:expr, $p1:expr $(,)?) => {};
3005    ($spec:expr, $p1:expr, $p2:expr $(,)?) => {
3006        entails_and_temp($spec, always($p1), always($p2));
3007        always_and_equality($p1, $p2);
3008    };
3009    ($spec:expr, $p1:expr, $p2:expr, $($tail:tt)*) => {
3010        entails_and_temp($spec, always($p1), always($p2));
3011        always_and_equality($p1, $p2);
3012        entails_always_and_n_internal!($spec, $p1.and($p2), $($tail)*);
3013    };
3014}
3015
3016pub use entails_always_and_n;
3017pub use entails_always_and_n_internal;
3018
3019#[macro_export]
3020macro_rules! always_and_equality_n {
3021    [$($tail:tt)*] => {
3022        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::always_and_equality_n_internal!($($tail)*));
3023    };
3024}
3025
3026#[macro_export]
3027macro_rules! always_and_equality_n_internal {
3028    ($p1:expr, $p2:expr $(,)?) => {
3029        always_and_equality($p1, $p2);
3030    };
3031    ($p1:expr, $p2:expr, $($tail:tt)*) => {
3032        always_and_equality($p1, $p2);
3033        always_and_equality_n_internal!($p1.and($p2), $($tail)*);
3034    };
3035}
3036
3037pub use always_and_equality_n;
3038pub use always_and_equality_n_internal;
3039
3040// □(lift_state(state_pred_and!(p1, p2, ..., pn))) == □(lift_state(p1)).and(□(lift_state(p2))).and(...).and(□(lift_state(pn)))
3041#[macro_export]
3042macro_rules! always_lift_state_and_equality_n {
3043    [$($tail:tt)*] => {
3044        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::always_lift_state_and_equality_n_internal!($($tail)*));
3045    };
3046}
3047
3048#[macro_export]
3049macro_rules! always_lift_state_and_equality_n_internal {
3050    ($p1:expr, $p2:expr $(,)?) => {
3051        always_lift_state_and_equality($p1, $p2);
3052    };
3053    ($p1:expr, $p2:expr, $($tail:tt)*) => {
3054        always_lift_state_and_equality($p1, $p2);
3055        always_lift_state_and_equality_n_internal!(state_pred_and!($p1, $p2), $($tail)*);
3056    };
3057}
3058
3059pub use always_lift_state_and_equality_n;
3060pub use always_lift_state_and_equality_n_internal;
3061
3062// Combine the premises of all the leads_to using or.
3063// ## Preconditions
3064//     spec ⊧ p1 ⇝ q
3065//     spec ⊧ p2 ⇝ q
3066//         ...
3067//     spec ⊧ pn ⇝ q
3068// ## Postconditions
3069//     spec ⊧ (p1 ∨ p2 ∨ ... ∨ pn) ⇝ q
3070//
3071// Usage: or_leads_to_combine_n!(spec, p1, p2, p3, p4; q)
3072#[macro_export]
3073macro_rules! or_leads_to_combine_n {
3074    [$($tail:tt)*] => {
3075        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::or_leads_to_combine_n_internal!($($tail)*));
3076    };
3077}
3078
3079#[macro_export]
3080macro_rules! or_leads_to_combine_n_internal {
3081    ($spec:expr, $p1:expr, $p2:expr; $q:expr) => {
3082        or_leads_to_combine($spec, $p1, $p2, $q);
3083    };
3084    ($spec:expr, $p1:expr, $p2:expr, $($rest:expr),+; $q:expr) => {
3085        or_leads_to_combine($spec, $p1, $p2, $q);
3086        or_leads_to_combine_n_internal!($spec, $p1.or($p2), $($rest),+; $q);
3087    };
3088}
3089
3090pub use or_leads_to_combine_n;
3091pub use or_leads_to_combine_n_internal;
3092
3093// Combine or_leads_to_combine and temp_pred_equality.
3094// The 'result' is the equivalent temporal predicate of joining all following predicates with ∨.
3095#[macro_export]
3096macro_rules! or_leads_to_combine_and_equality2 {
3097    ($spec:expr, $result:expr, $p1:expr, $($rest:expr),+; $q:expr) => {
3098        temp_pred_equality(
3099            $result,
3100            $p1$(.or($rest))+
3101        );
3102        or_leads_to_combine_n!($spec, $p1, $($rest),+; $q);
3103    }
3104}
3105
3106pub use or_leads_to_combine_and_equality2;
3107
3108// Leads to the conjunction of all the □q if leads to each of them.
3109// ## Preconditions
3110//     spec ⊧ p ⇝ □q1
3111//     spec ⊧ p ⇝ □q2
3112//        ...
3113//     spec ⊧ p ⇝ □qn
3114// ## Postconditions
3115//     spec ⊧ p ⇝ □(q1 ∧ q2 ∧ ... ∧ qn)
3116//
3117// Usage: leads_to_always_combine_n!(spec, p, q1, q2, q3, q4)
3118#[macro_export]
3119macro_rules! leads_to_always_combine_n {
3120    [$($tail:tt)*] => {
3121        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::leads_to_always_combine_n_internal!($($tail)*));
3122    };
3123}
3124
3125#[macro_export]
3126macro_rules! leads_to_always_combine_n_internal {
3127    ($spec:expr, $p:expr, $q1:expr, $q2:expr $(,)?) => {
3128        leads_to_always_combine($spec, $p, $q1, $q2);
3129    };
3130    ($spec:expr, $p:expr, $q1:expr, $q2:expr, $($tail:tt)*) => {
3131        leads_to_always_combine($spec, $p, $q1, $q2);
3132        always_and_equality($q1, $q2);
3133        leads_to_always_combine_n_internal!($spec, $p, $q1.and($q2), $($tail)*);
3134    };
3135}
3136
3137pub use leads_to_always_combine_n;
3138pub use leads_to_always_combine_n_internal;
3139
3140#[macro_export]
3141macro_rules! leads_to_always_combine_n_with_equality {
3142    [$($tail:tt)*] => {
3143        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::leads_to_always_combine_n_with_equality_internal!($($tail)*));
3144    };
3145}
3146
3147#[macro_export]
3148macro_rules! leads_to_always_combine_n_with_equality_internal {
3149    ($spec:expr, $p:expr, $dst:expr, $($tail:tt)*) => {
3150        temp_pred_equality($dst, combine_with_next!($($tail)*));
3151        leads_to_always_combine_n!($spec, $p, $($tail)*);
3152    };
3153}
3154
3155pub use leads_to_always_combine_n_with_equality;
3156pub use leads_to_always_combine_n_with_equality_internal;
3157
3158// Strengthen next with arbitrary number of predicates.
3159// ## Preconditions
3160//     spec ⊧ □p1
3161//     spec ⊧ □p2
3162//        ...
3163//     spec ⊧ □pn
3164//     p1 ∧ p2 ∧ ... ∧ pn ==> partial_spec
3165// ## Postconditions
3166//     spec ⊧ □all
3167//
3168// Usage: combine_spec_entails_always_n!(spec, partial_spec, p1, p2, p3, p4)
3169#[macro_export]
3170macro_rules! combine_spec_entails_always_n {
3171    [$($tail:tt)*] => {
3172        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::combine_spec_entails_always_n_internal!($($tail)*))
3173    }
3174}
3175
3176#[macro_export]
3177macro_rules! combine_spec_entails_always_n_internal {
3178    ($spec:expr, $partial_spec:expr, $($tail:tt)*) => {
3179        assert_by(
3180            valid($spec.implies(always(temp_pred_and!($($tail)*)))),
3181            {
3182                entails_always_and_n!($spec, $($tail)*);
3183            }
3184        );
3185        entails_preserved_by_always(temp_pred_and!($($tail)*), $partial_spec);
3186        entails_trans($spec, always(temp_pred_and!($($tail)*)), always($partial_spec));
3187    };
3188}
3189
3190pub use combine_spec_entails_always_n;
3191pub use combine_spec_entails_always_n_internal;
3192
3193// Combine multiple □ lift_state predicates using AND.
3194// ## Preconditions
3195//     spec ⊧ □lift_state(p1)
3196//     spec ⊧ □lift_state(p2)
3197//     ...
3198//     spec ⊧ □lift_state(pn)
3199// ## Postconditions
3200// spec ⊧ □lift_state(combine_state_pred!(p1, p2, ..., pn))  // spec ⊧ □lift_state(|s| p1(s) && p2(s) && ... && pn(s))
3201//
3202// Usage: entails_always_lift_state_and_n!(spec, p1, p2, p3, p4)
3203#[macro_export]
3204macro_rules! entails_always_lift_state_and_n {
3205    [$($tail:tt)*] => {
3206        ::vstd::prelude::verus_proof_macro_exprs!($crate::temporal_logic::rules::entails_always_lift_state_and_n_internal!($($tail)*))
3207    };
3208}
3209
3210#[macro_export]
3211macro_rules! entails_always_lift_state_and_n_internal {
3212    ($spec:expr, $p1:expr) => {
3213        // Single predicate case: nothing to do
3214    };
3215    ($spec:expr, $p1:expr, $p2:expr $(,)?) => {
3216        // Two predicate case: use entails_always_lift_state_and
3217        entails_always_lift_state_and($spec, $p1, $p2);
3218    };
3219    ($spec:expr, $p1:expr, $p2:expr, $p3:expr $(,)?) => {
3220        // Three predicate case: build step by step
3221        entails_always_lift_state_and($spec, $p1, $p2);
3222        let combined_p1_p2 = state_pred_and!($p1, $p2);
3223        entails_always_lift_state_and($spec, combined_p1_p2, $p3);
3224    };
3225    ($spec:expr, $p1:expr, $p2:expr, $($tail:expr),+ $(,)?) => {
3226        // Multi predicate case: recursively combine predicates
3227        entails_always_lift_state_and($spec, $p1, $p2);
3228        let combined_p1_p2 = state_pred_and!($p1, $p2);
3229        entails_always_lift_state_and_n_internal!($spec, combined_p1_p2, $($tail),+);
3230    };
3231}
3232
3233pub use entails_always_lift_state_and_n;
3234pub use entails_always_lift_state_and_n_internal;
3235
3236// Show that an spec entails the invariant by a group of action/state predicates which are also invariants entailed by spec.
3237// ## Preconditions
3238//     partial_spec ⊧ inv
3239//     spec ⊧ □p1
3240//     spec ⊧ □p2
3241//         ...
3242//     spec ⊧ □pn
3243//     p1 ∧ p2 ∧ ... ∧ pn ==> partial_spec
3244// ## Postconditions
3245//     spec ⊧ □inv
3246//
3247// Usage: invariant_n!(spec, partial_spec, inv, p1, p2, ..., pn)
3248#[macro_export]
3249macro_rules! invariant_n {
3250    [$($tail:tt)*] => {
3251        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::invariant_n_internal!($($tail)*))
3252    }
3253}
3254
3255#[macro_export]
3256macro_rules! invariant_n_internal {
3257    ($spec:expr, $partial_spec:expr, $inv:expr, $($tail:tt)*) => {
3258        assert_by(
3259            valid($spec.implies(always(temp_pred_and!($($tail)*)))),
3260            {
3261                entails_always_and_n!($spec, $($tail)*);
3262            }
3263        );
3264        entails_preserved_by_always(temp_pred_and!($($tail)*), $partial_spec);
3265        entails_trans($spec, always(temp_pred_and!($($tail)*)), always($partial_spec));
3266        entails_preserved_by_always($partial_spec, $inv);
3267        entails_trans($spec, always($partial_spec), always($inv));
3268    };
3269}
3270
3271pub use invariant_n;
3272pub use invariant_n_internal;
3273
3274// The conjunction of all the p is stable if each p is stable.
3275// ## Preconditions
3276//     ⊧ stable(p1)
3277//     ⊧ stable(p2)
3278//      ...
3279//     ⊧ stable(pn)
3280// ## Postconditions
3281//     ⊧ stable(p1 ∧ p2 ∧ ... ∧ pn)
3282//
3283// Usage: stable_and_n!(p1, p2, p3, p4)
3284#[macro_export]
3285macro_rules! stable_and_n {
3286    [$($tail:tt)*] => {
3287        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::stable_and_n_internal!($($tail)*));
3288    };
3289}
3290
3291#[macro_export]
3292macro_rules! stable_and_n_internal {
3293    ($p1:expr, $p2:expr $(,)?) => {
3294        stable_and_temp($p1, $p2);
3295    };
3296    ($p1:expr, $p2:expr, $($tail:tt)*) => {
3297        stable_and_temp($p1, $p2);
3298        stable_and_n_internal!($p1.and($p2), $($tail)*);
3299    };
3300}
3301
3302pub use stable_and_n;
3303pub use stable_and_n_internal;
3304
3305// The conjunction of all the p is stable if each p is stable.
3306// ## Postconditions
3307//     ⊧ stable(□p1 ∧ □p2 ∧ ... ∧ □pn)
3308//
3309// Usage: stable_and_always_n!(p1, p2, p3, p4)
3310#[macro_export]
3311macro_rules! stable_and_always_n {
3312    [$($tail:tt)*] => {
3313        ::verus_builtin_macros::verus_proof_macro_exprs!($crate::temporal_logic::rules::stable_and_always_n_internal!($($tail)*));
3314    };
3315}
3316
3317#[macro_export]
3318macro_rules! stable_and_always_n_internal {
3319    ($p1:expr, $($tail:expr),* $(,)?) => {
3320        always_p_is_stable($p1);
3321        $(always_p_is_stable($tail);)*
3322        stable_and_n!(always($p1), $(always($tail)),*);
3323    };
3324}
3325
3326pub use stable_and_always_n;
3327pub use stable_and_always_n_internal;
3328
3329// Implies new invariant from multiple proved invariants.
3330// ## Preconditions
3331//     ⊧ init ⇒ inv
3332//     ⊧ inv ∧ p1 ∧ p2 ∧ ... ∧ pn ∧ next ⇒ inv'
3333//     spec ⊧ lift_state(init)
3334//     spec ⊧ □(lift_action(next))
3335//     spec ⊧ □lift_state(p1)
3336//     spec ⊧ □lift_state(p2)
3337//     ...
3338//     spec ⊧ □lift_state(pn)
3339// ## Postconditions
3340//     spec ⊧ □lift_state(inv)
3341//
3342// Usage: implies_new_invariant_n!(spec, init, next, inv, p1, p2, p3, ...)
3343#[macro_export]
3344macro_rules! implies_new_invariant_n {
3345    [$($tail:tt)*] => {
3346        ::vstd::prelude::verus_proof_macro_exprs!($crate::temporal_logic::rules::implies_new_invariant_n_internal!($($tail)*))
3347    };
3348}
3349
3350#[macro_export]
3351macro_rules! implies_new_invariant_n_internal {
3352    ($spec:expr, $init:expr, $next:expr, $inv:expr, $p1:expr) => {
3353        implies_new_invariant($spec, $init, $next, $inv, $p1);
3354    };
3355    ($spec:expr, $init:expr, $next:expr, $inv:expr, $p1:expr,) => {
3356        implies_new_invariant_n_internal!($spec, $init, $next, $inv, $p1);
3357    };
3358    ($spec:expr, $init:expr, $next:expr, $inv:expr, $($preds:expr),+) => {
3359        {
3360            let combined_pred = state_pred_and!($($preds),+);
3361            entails_always_lift_state_and_n!($spec, $($preds),+);
3362            implies_new_invariant($spec, $init, $next, $inv, combined_pred);
3363        }
3364    };
3365    ($spec:expr, $init:expr, $next:expr, $inv:expr, $($preds:expr),+ ,) => {
3366        implies_new_invariant_n_internal!($spec, $init, $next, $inv, $($preds),+);
3367    };
3368}
3369
3370pub use implies_new_invariant_n;
3371pub use implies_new_invariant_n_internal;
3372
3373// Strengthen wf1_by_borrowing_inv with multiple invariants.
3374// ## Preconditions
3375//     spec ⊧ □next
3376//     spec ⊧ □inv1
3377//     spec ⊧ □inv2
3378//        ...
3379//     spec ⊧ □invn
3380//     ⊧ p ∧ inv1 ∧ inv2 ∧ ... ∧ invn ∧ next ⇒ p' ∨ q'
3381//     ⊧ p ∧ inv1 ∧ inv2 ∧ ... ∧ invn ∧ next ∧ forward ⇒ q'
3382//     ⊧ p ∧ inv1 ∧ inv2 ∧ ... ∧ invn ⇒ enabled(forward)
3383//     spec ⊧ wf(forward)
3384// ## Postconditions
3385//     spec ⊧ p ⇝ q
3386// Usage: wf1_by_borrowing_inv_n!(spec, next, forward, p, q, inv1, inv2, inv3, ...)
3387#[macro_export]
3388macro_rules! wf1_by_borrowing_inv_n {
3389    ($spec:expr, $next:expr, $forward:expr, $p:expr, $q:expr, $($inv:expr),+ $(,)?) => {{
3390        entails_always_lift_state_and_n!($spec, $($inv),+);
3391        // Explicitly call the base case to ensure we have the needed condition
3392        let combined_inv = state_pred_and!($($inv),+);
3393        // After entails_always_lift_state_and_n!, we should have spec.entails(always(lift_state(combined_inv)))
3394        wf1_by_borrowing_inv($spec, $next, $forward, $p, $q, combined_inv)
3395    }};
3396}
3397
3398pub use wf1_by_borrowing_inv_n;
3399
3400// Apply always_lift_state_weaken with multiple predicates.
3401// ## Preconditions
3402//     forall |s| p1(s) && p2(s) && ... && pn(s) ==> h(s)
3403//     spec ⊧ □lift_state(p1)
3404//     spec ⊧ □lift_state(p2)
3405//     ...
3406//     spec ⊧ □lift_state(pn)
3407// ## Postconditions
3408//     spec ⊧ □lift_state(h)
3409//
3410// Usage: always_lift_state_weaken_n!(spec, p1, p2, p3, ..., h)
3411#[macro_export]
3412macro_rules! always_lift_state_weaken_n {
3413    [$($tail:tt)*] => {
3414        ::vstd::prelude::verus_proof_macro_exprs!($crate::temporal_logic::rules::always_lift_state_weaken_n_internal!($($tail)*))
3415    };
3416}
3417
3418#[macro_export]
3419macro_rules! always_lift_state_weaken_n_internal {
3420    ($spec:expr, $p1:expr, $h:expr) => {
3421        always_lift_state_weaken($spec, $p1, $h);
3422    };
3423    ($spec:expr, $p1:expr, $p2:expr, $h:expr) => {
3424        entails_always_lift_state_and_n!($spec, $p1, $p2);
3425        always_lift_state_weaken($spec, state_pred_and!($p1, $p2), $h);
3426    };
3427    ($spec:expr, $p1:expr, $p2:expr, $h:expr,) => {
3428        always_lift_state_weaken_n_internal!($spec, $p1, $p2, $h);
3429    };
3430    ($spec:expr, $p1:expr, $p2:expr, $($tail:expr),+ , $h:expr) => {
3431        entails_always_lift_state_and_n!($spec, $p1, $p2, $($tail),+);
3432        always_lift_state_weaken($spec, state_pred_and!($p1, $p2, $($tail),+), $h);
3433    };
3434    ($spec:expr, $p1:expr, $p2:expr, $($tail:expr),+ , $h:expr,) => {
3435        always_lift_state_weaken_n_internal!($spec, $p1, $p2, $($tail),+ , $h);
3436    };
3437}
3438
3439pub use always_lift_state_weaken_n;
3440pub use always_lift_state_weaken_n_internal;
3441
3442pub broadcast group group_tla_rules {
3443    state_pred_and_apply_equality,
3444    state_pred_or_apply_equality,
3445    state_pred_implies_apply_equality,
3446    state_pred_not_apply_equality,
3447    lift_state_and_equality,
3448    lift_state_or_equality,
3449    lift_state_not_equality,
3450    lift_state_implies_equality,
3451    entails_and_temp,
3452    entails_and_temp_reverse,
3453    entails_or_temp,
3454    entails_not_temp_reverse,
3455    entails_implies_temp_reverse,
3456    always_lift_state_and_equality,
3457    always_implies_to_leads_to,
3458    always_to_always_later,
3459    always_double_equality,
3460    always_and_equality,
3461    tla_forall_apply,
3462    spec_entails_tla_forall,  // may slow down proofs
3463    always_implies_forall_intro,  // may slow down proofs
3464    tla_exists_leads_to_intro,  // may slow down proofs
3465    leads_to_self_temp,
3466    entails_and_different_temp,
3467    always_p_is_stable,
3468    stable_and_temp,
3469    entails_preserved_by_always,
3470    leads_to_apply,  // may slow down proofs
3471    or_leads_to_combine,
3472    leads_to_always_combine,
3473    leads_to_framed_by_or,
3474    lift_state_exists_equality,
3475    implies_tla_exists_intro,
3476    leads_to_tla_exists_intro,
3477    state_exists_intro,  // may be unnecessary
3478    entails_always_lift_state_and,  // may slow down proofs
3479    entails_always_lift_state_and_elim,
3480    entails_tla_exists_by_witness,  // may slow down proofs
3481    lift_state_exists_leads_to_intro,
3482    lift_state_exists_absorb_equality,
3483    lift_state_forall_absorb_equality,
3484    lift_state_not_equality,
3485}
3486
3487} // verus!