-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathMuddyChildrenRounds.v
2241 lines (2116 loc) · 92.6 KB
/
MuddyChildrenRounds.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
From VLSM.Lib Require Import Itauto.
From stdpp Require Import prelude finite.
From VLSM.Core Require Import VLSM VLSMProjections Composition.
From VLSM.Lib Require Import Preamble EquationsExtras ListExtras FinSetExtras.
From VLSM.Core Require Import ConstrainedVLSM.
(** * Tutorial: Round-Based Asynchronous Muddy Children Puzzle
This module formalizes the Muddy Children (MC) puzzle
as a constrained composition of VLSMs that communicate
asynchronously in rounds. The module provides an advanced
self-contained example of modeling and reasoning with VLSMs.
Consider a
#<a href="https://plato.stanford.edu/entries/dynamic-epistemic/appendix-B-solutions.html">
standard statement of the MC puzzle</a>#:
"Three children are playing in the mud. Father calls the children to the house,
arranging them in a semicircle so that each child can clearly see every other
child. _At least one of you has mud on your forehead_, says Father.
The children look around, each examining every other child's forehead.
Of course, no child can examine his or her own. Father continues,
_If you know whether your forehead is dirty, then step forward now_.
No child steps forward. Father repeats himself a second time,
_If you know whether your forehead is dirty, then step forward now_.
Some but not all of the children step forward. Father repeats himself a third
time, _If you know whether your forehead is dirty, then step forward now_.
All of the remaining children step forward. How many children have muddy foreheads?"
We alter the puzzle in two ways:
- we allow an arbitrary but fixed number of children, and
- we allow the children to communicate asynchronously.
To allow asynchronous communication, we let each child maintain the "round"
they perceive themselves to be in and to communicate their round number to their peers.
We define some VLSM-specific notions in the
context of the MC puzzle (such as labels, states, initial states,
messages, transitions, valid transitions, and composition constraints),
but there are also some MC-specific notions (final state,
consistent state, observation equivalence, and invariant).
The consistency property of states guarantees that a state adheres
to the assumptions in the puzzle's statement:
- there is at least one muddy child, and
- any child sees all the muddy children except themselves.
Final states are those states in which each child has decided on a status,
i.e., as muddy or clean.
The main result in the module is the theorem [MC_safety], which establishes
that final states are reachable from any non-initial valid state.
The proof is based on the lemmas [MC_composite_invariant_preservation],
[MC_progress] and [MC_round_bound].
*)
(** ** Basic definitions *)
Inductive Label : Type :=
| init
| emit
| receive.
Inductive ChildStatus : Type :=
| undecided
| muddy
| clean.
Record RoundStatus : Type := mkRS
{
rs_round : nat;
rs_status : ChildStatus;
}.
(** Show [RoundStatus] using the constructor instead of the record syntax. *)
Add Printing Constructor RoundStatus.
Section sec_muddy.
Context
(index : Type)
`{finite.Finite index}
`{Inhabited index}
`{FinSet index indexSet}
.
(**
Children maintain the set of (indices of) other children they perceive
as being muddy and (except for their initial state) the current round they
perceive themselves to be at and their [ChildStatus].
*)
Record State : Type := mkSt
{
st_obs : indexSet;
st_rs : option RoundStatus;
}.
(** Show [State] using the constructor instead of the record syntax. *)
Add Printing Constructor State.
(**
A message carries the identity of its sender, and shares the round number
and their [ChildStatus].
*)
Record Message : Type := mkMsg
{
msg_index : index;
msg_round : nat;
msg_status : ChildStatus;
}.
(** Show [Message] using the constructor instead of the record syntax. *)
Add Printing Constructor Message.
Definition MCType : VLSMType Message :=
{|
state := State;
label := Label;
|}.
Definition MC_initial_state_prop (s : State) : Prop :=
st_rs s = None.
Equations MC_transition (i : index) (l : Label)
(s : State) (om : option Message) : State * option Message :=
MC_transition i init (mkSt o None) None with size o :=
{ | 0 => (mkSt o (Some (mkRS 0 muddy)), None)
| S _ => (mkSt o (Some (mkRS 0 undecided)), None)
};
MC_transition i emit (mkSt o (Some (mkRS r status))) None :=
((mkSt o (Some (mkRS r status))), Some (mkMsg i r status));
MC_transition i receive (mkSt o (Some (mkRS r undecided))) (Some (mkMsg j r' clean))
with decide (j ∈ o) :=
{ | right Hin =>
if decide (r' = size o) then
(mkSt o (Some (mkRS r' clean)), None)
else if decide (r' = size o + 1) then
(mkSt o (Some (mkRS (r' - 1) muddy)), None)
else (mkSt o (Some (mkRS r undecided)), None)
| left Hin => (mkSt o (Some (mkRS r undecided)), None)
};
MC_transition i receive (mkSt o (Some (mkRS r undecided))) (Some (mkMsg j r' muddy))
with decide (j ∈ o) :=
{ | left Hin =>
if decide (r' = size o) then
(mkSt o (Some (mkRS r' muddy)), None)
else if decide (r' = size o - 1) then
(mkSt o (Some (mkRS (r' + 1) clean)), None)
else (mkSt o (Some (mkRS r undecided)), None)
| right Hin => (mkSt o (Some (mkRS r undecided)), None)
};
(**
One of the most interesting cases of the transition function is the one when
a child [i] who doesn't know their status receives a message from a child [j]
who also doesn't know their own status. However, being at round [r'], [j] knows
there are more than [r'] muddy children.
*)
MC_transition i receive (mkSt o (Some (mkRS r undecided))) (Some (mkMsg j r' undecided))
(**
If child [i] sees [j] as muddy, they can infer that there are actually more than
[r' + 1] muddy children.
*)
with decide (j ∈ o) :=
{ | left Hin =>
(**
If [r' + 1] is less than or equal to the current round number of [i], then
the round doesn't change and the status remains undecided.
*)
if decide (r' < r) then
(mkSt o (Some (mkRS r undecided)), None)
(**
Else, we update the round number to [r' + 1], and have to compare it to
the number of muddy children seen by child [i].
If its less than that, the information gained is not useful enough to
infer anything, so the status remains undecided.
*)
else if decide (r <= r' < size o - 1) then
(mkSt o (Some (mkRS (r' + 1) undecided)), None)
(**
Else, if the updated round ever becomes equal to the number of muddy children
seen by [i], they can conclude they are muddy.
*)
else if decide (r' = size o - 1) then
(mkSt o (Some (mkRS (r' + 1) muddy)), None)
else (mkSt o (Some (mkRS r undecided)), None)
| right Hin =>
if decide (r' <= r) then
(mkSt o (Some (mkRS r undecided)), None)
else if decide (r < r' < size o) then
(mkSt o (Some (mkRS r' undecided)), None)
else if decide (r' = size o) then
(mkSt o (Some (mkRS r' muddy)), None)
else (mkSt o (Some (mkRS r undecided)), None)
};
MC_transition _ _ s _ := (s, None).
Definition state_status (s : option RoundStatus) : ChildStatus :=
from_option rs_status undecided s.
Definition state_round (s : option RoundStatus) : nat :=
from_option rs_round 0 s.
Definition state_round_inc (s : State) : nat :=
match st_rs s with
| Some rs => S (rs_round rs)
| _ => 0
end.
Definition message_status (om : option Message) : ChildStatus :=
from_option msg_status undecided om.
Definition message_round (om : option Message) : nat :=
from_option msg_round 0 om.
Definition message_index (om : option Message) (i : index) : index :=
from_option msg_index i om.
Inductive MC_valid : Label -> State -> option Message -> Prop :=
| MC_valid_init : forall o : indexSet,
MC_valid init (mkSt o None) None
| MC_valid_emit : forall (o : indexSet) (rs : RoundStatus),
MC_valid emit (mkSt o (Some rs)) None
| MC_valid_receive : forall (o : indexSet) (rs : RoundStatus) (m : Message),
MC_valid receive (mkSt o (Some rs)) (Some m).
#[export] Instance ChildStatus_eq_dec : EqDecision ChildStatus.
Proof. by intros x y; unfold Decision; decide equality. Qed.
Definition MC_initial_state_type : Type :=
{st : State | MC_initial_state_prop st}.
Program Definition MC_initial_state : MC_initial_state_type :=
exist _ (mkSt ∅ None) _.
Next Obligation.
Proof. done. Qed.
#[export] Instance Decision_MC_initial_state_prop :
forall s, Decision (MC_initial_state_prop s).
Proof. by typeclasses eauto. Qed.
#[export] Instance Inhabited_MC_initial_state_type : Inhabited (MC_initial_state_type) :=
populate (MC_initial_state).
Definition MCMachine (i : index) : VLSMMachine MCType :=
{|
initial_state_prop := MC_initial_state_prop;
initial_message_prop := const False;
transition := fun l '(st, om) => MC_transition i l st om;
valid := fun l '(st, om) => MC_valid l st om;
|}.
Definition MCVLSM (i : index) : VLSM Message :=
{|
vlsm_type := MCType;
vlsm_machine := MCMachine i;
|}.
#[export] Instance MC_composite_initial_state_dec :
forall s, Decision (composite_initial_state_prop MCVLSM s).
Proof.
intros s; eapply @Decision_iff with
(P := Forall (fun n : index => initial_state_prop (MCVLSM n) (s n)) (enum index)).
- rewrite Forall_forall; apply forall_proper.
split; [| done].
by intros Hx; apply Hx, elem_of_enum.
- by typeclasses eauto.
Qed.
Definition MuddyUnion (s : composite_state MCVLSM) : indexSet :=
⋃ (map (fun i => st_obs (s i)) (enum index)).
Lemma MuddyUnion_elem (s : composite_state MCVLSM) (i j : index) :
i ∈ st_obs (s j) -> i ∈ MuddyUnion s.
Proof.
intros Hobs.
apply elem_of_union_list.
exists (st_obs (s j)); split; [| done].
apply elem_of_list_fmap.
exists j; split; [done |].
by apply elem_of_enum.
Qed.
Definition consistent (s : composite_state MCVLSM) : Prop :=
MuddyUnion s ≢ ∅ /\ forall n : index, st_obs (s n) ≡ MuddyUnion s ∖ {[n]}.
Definition MC_no_equivocation (s : composite_state MCVLSM) (m : Message) : Prop :=
match m with
| mkMsg n r' status' =>
match s n with
| mkSt _ (Some (mkRS r status)) =>
(status' = status /\ r' = r) \/ (status' = undecided /\ r' < r)
| _ => False
end
end.
Inductive MC_no_equivocation_inductive : composite_state MCVLSM -> Message -> Prop :=
| MC_no_equivocation_inductive_msg_eq : forall s n o r status,
s n = mkSt o (Some (mkRS r status)) ->
MC_no_equivocation_inductive s (mkMsg n r status)
| MC_no_equivocation_inductive_undecided : forall s n o r r' status,
s n = mkSt o (Some (mkRS r status)) ->
r' < r ->
MC_no_equivocation_inductive s (mkMsg n r' undecided).
Lemma MC_no_equivocation_inductive_equiv :
forall s m, MC_no_equivocation s m <-> MC_no_equivocation_inductive s m.
Proof.
split; destruct m; cbn.
- repeat case_match; [| done].
intros [[] | []]; subst.
+ by eapply MC_no_equivocation_inductive_msg_eq; eauto.
+ by eapply MC_no_equivocation_inductive_undecided; eauto.
- by repeat case_match; inversion 1; itauto congruence.
Qed.
Definition MC_constraint
(l : composite_label MCVLSM) (sm : composite_state MCVLSM * option Message) : Prop :=
match l, sm with
| existT _ init, (s, _) => consistent s
| existT _ receive, (s, Some m) => MC_no_equivocation s m
| _, _ => True
end.
Definition MC_composite_vlsm : VLSM Message :=
composite_vlsm MCVLSM MC_constraint.
Definition MC_final_state (s : composite_state MCVLSM) : Prop :=
forall n : index, state_status (st_rs (s n)) <> undecided.
Definition MC_initial_consistent_state (s : composite_state MCVLSM) : Prop :=
composite_initial_state_prop MCVLSM s /\ consistent s.
Definition MC_non_initial_valid_state (s : composite_state MCVLSM) : Prop :=
valid_state_prop MC_composite_vlsm s /\ ~ (composite_initial_state_prop MCVLSM s).
Definition MC_obs_equivalence (s1 s2 : composite_state MCVLSM) : Prop :=
forall n : index, st_obs (s1 n) ≡ st_obs (s2 n).
#[export] Instance MC_obs_equiv_refl : Reflexive MC_obs_equivalence.
Proof. done. Qed.
#[export] Instance MC_obs_equiv_symm : Symmetric MC_obs_equivalence.
Proof. by unfold MC_obs_equivalence; intros x y Hxy. Qed.
#[export] Instance MC_obs_equiv_trans : Transitive MC_obs_equivalence.
Proof.
by unfold MC_obs_equivalence; intros s1 s2 s3 H12 H23;
etransitivity; [apply H12 | apply H23].
Qed.
#[export] Instance MC_obs_equiv_equiv : Equivalence MC_obs_equivalence.
Proof. by split; typeclasses eauto. Qed.
Lemma MC_state_update_preserves_obs_equiv
(s : composite_state MCVLSM) (i : index) (si : State) :
st_obs (s i) ≡ st_obs si -> MC_obs_equivalence s (state_update MCVLSM s i si).
Proof.
by intros Hobs n; destruct (decide (n = i)); subst; state_update_simpl.
Qed.
Lemma MC_obs_equiv_preserves_muddy (s1 s2 : composite_state MCVLSM) :
MC_obs_equivalence s1 s2 -> MuddyUnion s1 ≡ MuddyUnion s2.
Proof.
intros Hobs; unfold MuddyUnion.
intros i; rewrite !elem_of_union_list.
split; intros (X & HX & Hi); apply elem_of_list_fmap in HX as (y & -> & Hy).
- exists (st_obs (s2 y)); split.
+ by apply elem_of_list_fmap; exists y.
+ by apply Hobs.
- exists (st_obs (s1 y)); split.
+ by apply elem_of_list_fmap; exists y.
+ by apply Hobs.
Qed.
Lemma MC_obs_equiv_preserves_consistency (s1 s2 : composite_state MCVLSM) :
MC_obs_equivalence s1 s2 -> consistent s1 -> consistent s2.
Proof.
intros Hobs [Hnempty Hcons]; split.
- unfold MuddyUnion in Hnempty |- *.
rewrite empty_union_list, Forall_forall in Hnempty |- *.
contradict Hnempty.
intros x Hx.
apply elem_of_list_fmap in Hx as (j & -> & _).
unfold MC_obs_equivalence in Hobs; rewrite Hobs.
apply Hnempty, elem_of_list_fmap.
exists j; split; [done |].
by apply elem_of_enum.
- intros j x.
rewrite <- MC_obs_equiv_preserves_muddy by done.
unfold MC_obs_equivalence in Hobs; rewrite <- Hobs.
by apply Hcons.
Qed.
Lemma MC_trans_preserves_obs_equiv (s : composite_state MCVLSM) :
forall (l : composite_label MCVLSM) (s' : composite_state MCVLSM) (m m' : option Message),
composite_transition (MCVLSM) l (s, m) = (s', m') -> MC_obs_equivalence s s'.
Proof.
intros; unfold composite_transition in H9.
destruct l as [i li], (transition li (s i, m)) eqn: Ht;
cbn in Ht; inversion H9; subst; clear H9.
apply MC_state_update_preserves_obs_equiv.
destruct s0, (s i).
revert Ht.
by apply FunctionalElimination_MC_transition; intros; inversion Ht;
subst; try done; repeat case_decide; inversion H10.
Qed.
Lemma MC_in_futures_preserves_obs_equiv
(s s' : composite_state MCVLSM)
(Hfutures : in_futures MC_composite_vlsm s s') :
MC_obs_equivalence s s'.
Proof.
apply (in_futures_preserving MC_composite_vlsm); [.. | done].
- by split; typeclasses eauto.
- intros s1 s2 l om1 om2 [].
by apply MC_trans_preserves_obs_equiv with l om1 om2.
Qed.
Lemma MC_in_futures_preserves_muddy
(s s' : composite_state MCVLSM) (Hfutures : in_futures MC_composite_vlsm s s') :
MuddyUnion s ≡ MuddyUnion s'.
Proof.
by intros; apply MC_obs_equiv_preserves_muddy, MC_in_futures_preserves_obs_equiv.
Qed.
Lemma MC_in_futures_preserves_consistency
(s s' : composite_state MCVLSM) (Hfutures : in_futures MC_composite_vlsm s s') :
consistent s <-> consistent s'.
Proof.
unfold consistent.
apply MC_in_futures_preserves_obs_equiv in Hfutures as Hfutures'.
unfold MC_obs_equivalence in Hfutures'.
setoid_rewrite Hfutures'.
apply MC_in_futures_preserves_muddy in Hfutures.
by setoid_rewrite Hfutures.
Qed.
Lemma MC_non_initial_valid_consistent :
forall (s : composite_state MCVLSM), MC_non_initial_valid_state s -> consistent s.
Proof.
intros s [Hvalid Hnon_initial].
induction Hvalid using valid_state_prop_ind; [done |].
destruct Ht as [(_ & _ & Hv & Hc) Ht].
destruct (decide (composite_initial_state_prop MCVLSM s)).
- destruct l as [i []]; cbn in Hv.
+ eapply MC_obs_equiv_preserves_consistency; [| done].
by eapply MC_trans_preserves_obs_equiv
with (s := s) (l := existT i init) (m := om) (m' := om').
+ by inversion Hv; specialize (c i); rewrite <- H9 in c.
+ by inversion Hv; specialize (c i); rewrite <- H9 in c.
- eapply MC_obs_equiv_preserves_consistency; [| by apply IHHvalid].
by apply MC_trans_preserves_obs_equiv
with (s := s) (l := l) (m := om) (m' := om').
Qed.
Lemma MC_muddy_number_of_muddy_seen (s : composite_state MCVLSM) (j : index) :
consistent s ->
j ∈ MuddyUnion s ->
size (st_obs (s j)) = size (MuddyUnion s) - 1.
Proof.
intros [Hnempty Hn] n.
rewrite Hn, size_difference.
- by rewrite size_singleton.
- by rewrite singleton_subseteq_l.
Qed.
Lemma MC_muddy_number_of_muddy_seen_iff (s : composite_state MCVLSM) (j : index) :
consistent s ->
j ∈ MuddyUnion s <-> size (st_obs (s j)) = size (MuddyUnion s) - 1.
Proof.
intros [Hnempty Hn].
split; [by apply MC_muddy_number_of_muddy_seen |].
intros Hsize.
rewrite Hn, size_difference_alt in Hsize.
destruct (decide (size (MuddyUnion s) = 0));
[by apply size_non_empty_iff in Hnempty |].
cut (size (MuddyUnion s ∩ {[j]}) ≠ 0).
{
intros Hsizennull.
apply size_non_empty_iff in Hsizennull.
by set_solver.
}
by lia.
Qed.
Lemma MC_clean_number_of_muddy_seen (s : composite_state MCVLSM) (j : index) :
consistent s ->
j ∉ MuddyUnion s ->
size (st_obs (s j)) = size (MuddyUnion s).
Proof.
intros [Hnempty Hn] n.
rewrite Hn, size_difference_alt.
replace (size (MuddyUnion s ∩ {[j]})) with 0; [by lia |].
by symmetry; apply size_empty_iff; set_solver.
Qed.
Lemma MC_clean_number_of_muddy_seen_iff (s : composite_state MCVLSM) (j : index) :
consistent s ->
j ∉ MuddyUnion s <-> size (st_obs (s j)) = size (MuddyUnion s).
Proof.
intros [Hnempty Hn].
split; [by apply MC_clean_number_of_muddy_seen |].
intros Hsize.
rewrite Hn, size_difference_alt in Hsize.
destruct (decide (size (MuddyUnion s) = 0));
[by apply size_non_empty_iff in Hnempty |].
cut (size (MuddyUnion s ∩ {[j]}) = 0).
{
intros Hsize0.
apply size_empty_iff in Hsize0.
by set_solver.
}
by lia.
Qed.
Lemma MC_number_of_muddy_seen (s : composite_state MCVLSM) :
consistent s ->
forall n, size (st_obs (s n)) <= size (MuddyUnion s) <= size (st_obs (s n)) + 1.
Proof.
intros Hcons n.
destruct (decide (n ∈ MuddyUnion s)) as [Hdec | Hdec].
- by apply MC_muddy_number_of_muddy_seen in Hdec as ->; [lia |].
- by apply MC_clean_number_of_muddy_seen in Hdec as ->; [lia |].
Qed.
Lemma MC_transition_undecided_receive_clean_round_obs :
forall (i : index) (s : State) (m : Message),
state_status (st_rs s) = undecided ->
msg_status m = clean ->
msg_index m ∉ st_obs s ->
msg_round m = size (st_obs s) ->
MC_transition i receive
(mkSt (st_obs s) (Some (mkRS (state_round (st_rs s)) (state_status (st_rs s)))))
(Some (mkMsg (msg_index m) (msg_round m) (msg_status m)))
=
(mkSt (st_obs s) (Some (mkRS (msg_round m) clean)), None).
Proof.
by intros; rewrite H9, H10, MC_transition_equation_9;
unfold MC_transition_clause_3; repeat case_decide.
Qed.
Lemma MC_transition_undecided_receive_clean_round_obs_plus_one :
forall (i : index) (s : State) (m : Message),
state_status (st_rs s) = undecided ->
msg_status m = clean ->
msg_index m ∉ st_obs s ->
msg_round m = size (st_obs s) + 1 ->
MC_transition i receive
(mkSt (st_obs s) (Some (mkRS (state_round (st_rs s)) (state_status (st_rs s)))))
(Some (mkMsg (msg_index m) (msg_round m) (msg_status m)))
=
(mkSt (st_obs s) (Some (mkRS (msg_round m - 1) muddy)), None).
Proof.
by intros; rewrite H9, H10, MC_transition_equation_9;
unfold MC_transition_clause_3; repeat case_decide; try done; lia.
Qed.
Lemma MC_transition_undecided_receive_muddy_round_obs :
forall (i : index) (s : State) (m : Message),
state_status (st_rs s) = undecided ->
msg_status m = muddy ->
msg_index m ∈ st_obs s ->
msg_round m = size (st_obs s) ->
MC_transition i receive
(mkSt (st_obs s) (Some (mkRS (state_round (st_rs s)) (state_status (st_rs s)))))
(Some (mkMsg (msg_index m) (msg_round m) (msg_status m)))
=
(mkSt (st_obs s) (Some (mkRS (msg_round m) muddy)), None).
Proof.
by intros; rewrite H9, H10, MC_transition_equation_8;
unfold MC_transition_clause_4; repeat case_decide.
Qed.
Lemma MC_transition_undecided_receive_muddy_round_obs_minus_one :
forall (i : index) (s : State) (m : Message),
state_status (st_rs s) = undecided ->
msg_status m = muddy ->
msg_index m ∈ st_obs s ->
msg_round m = size (st_obs s) - 1 ->
MC_transition i receive
(mkSt (st_obs s) (Some (mkRS (state_round (st_rs s)) (state_status (st_rs s)))))
(Some (mkMsg (msg_index m) (msg_round m) (msg_status m)))
=
(mkSt (st_obs s) (Some (mkRS (msg_round m + 1) clean)), None).
Proof.
intros; rewrite H9, H10, MC_transition_equation_8;
unfold MC_transition_clause_4; repeat case_decide; [| done..].
destruct (decide (size (st_obs s) = 0)); [| by lia].
by apply non_empty_inhabited, size_non_empty_iff in H11.
Qed.
Lemma MC_transition_undecided_receive_undecided_round_obs_minus_one :
forall (i : index) (s : State) (m : Message),
state_status (st_rs s) = undecided ->
msg_status m = undecided ->
msg_index m ∈ st_obs s ->
msg_round m = size (st_obs s) - 1 ->
state_round (st_rs s) < size (st_obs s) ->
MC_transition i receive
(mkSt (st_obs s) (Some (mkRS (state_round (st_rs s)) (state_status (st_rs s)))))
(Some (mkMsg (msg_index m) (msg_round m) (msg_status m)))
=
(mkSt (st_obs s) (Some (mkRS (msg_round m + 1) muddy)), None).
Proof.
by intros; rewrite H9, H10, MC_transition_equation_7;
unfold MC_transition_clause_5; repeat case_decide; try done; lia.
Qed.
Lemma MC_transition_undecided_receive_undecided_round_obs :
forall (i : index) (s : State) (m : Message),
state_status (st_rs s) = undecided ->
msg_status m = undecided ->
msg_index m ∉ st_obs s ->
msg_round m = size (st_obs s) ->
state_round (st_rs s) < size (st_obs s) ->
MC_transition i receive
(mkSt (st_obs s) (Some (mkRS (state_round (st_rs s)) (state_status (st_rs s)))))
(Some (mkMsg (msg_index m) (msg_round m) (msg_status m)))
=
(mkSt (st_obs s) (Some (mkRS (msg_round m) muddy)), None).
Proof.
by intros; rewrite H9, H10, MC_transition_equation_7;
unfold MC_transition_clause_5; repeat case_decide; try done; lia.
Qed.
Lemma MC_transition_undecided_receive_undecided_round_lt_obs_minus_one :
forall (i : index) (s : State) (m : Message),
state_status (st_rs s) = undecided ->
msg_status m = undecided ->
msg_index m ∈ st_obs s ->
state_round (st_rs s) <= msg_round m < size (st_obs s) - 1 ->
state_round (st_rs s) < size (st_obs s) ->
MC_transition i receive
(mkSt (st_obs s) (Some (mkRS (state_round (st_rs s)) (state_status (st_rs s)))))
(Some (mkMsg (msg_index m) (msg_round m) (msg_status m)))
=
(mkSt (st_obs s) (Some (mkRS (msg_round m + 1) (state_status (st_rs s)))), None).
Proof.
by intros; rewrite H9, H10, MC_transition_equation_7;
unfold MC_transition_clause_5; repeat case_decide; try done; lia.
Qed.
(** ** Invariant preservation *)
Definition MC_component_invariant_helper (s : State) (union : indexSet) : Prop :=
match state_status (st_rs s) with
| undecided => state_round (st_rs s) < size (st_obs s)
| clean => state_round (st_rs s) = size (st_obs s) /\ size union = size (st_obs s)
| muddy => state_round (st_rs s) = size (st_obs s) /\ size union - 1 = size (st_obs s)
end.
Definition MC_component_invariant (s : composite_state MCVLSM) (i : index) : Prop :=
MC_component_invariant_helper (s i) (MuddyUnion s).
Inductive MC_component_invariant_inductive : composite_state MCVLSM -> index -> Prop :=
| component_invariant_undecided : forall s i,
state_status (st_rs (s i)) = undecided ->
state_round (st_rs (s i)) < size (st_obs (s i)) ->
MC_component_invariant_inductive s i
| component_invariant_clean : forall s i,
state_status (st_rs (s i)) = clean ->
state_round (st_rs (s i)) = size (st_obs (s i)) ->
size (MuddyUnion s) = size (st_obs (s i)) ->
MC_component_invariant_inductive s i
| component_invariant_muddy : forall s i,
state_status (st_rs (s i)) = muddy ->
state_round (st_rs (s i)) = size (st_obs (s i)) ->
size (MuddyUnion s) - 1 = size (st_obs (s i)) ->
MC_component_invariant_inductive s i.
Lemma MC_component_invariant_equiv_MC_component_invariant_inductive :
forall (s : composite_state MCVLSM) (i : index),
MC_component_invariant s i <-> MC_component_invariant_inductive s i.
Proof.
intros s i.
unfold MC_component_invariant, MC_component_invariant_helper.
case_match; split; intros.
- by apply component_invariant_undecided.
- by inversion H10; [| congruence..].
- by apply component_invariant_muddy; destruct H10.
- by inversion H10; split; congruence.
- by apply component_invariant_clean; destruct H10.
- by inversion H10; split; congruence.
Qed.
Definition MC_composite_invariant (s : composite_state MCVLSM) : Prop :=
forall (i : index),
initial_state_prop (MCVLSM i) (s i) \/ MC_component_invariant s i.
Definition MC_composite_invariant_inductive (s : composite_state MCVLSM) : Prop :=
forall (i : index),
initial_state_prop (MCVLSM i) (s i) \/ MC_component_invariant_inductive s i.
Lemma MC_composite_invariant_preservation_muddy_from_undecided
(s sm : composite_state MCVLSM) (i j : index) (o : indexSet) :
o ≡ st_obs (s i) ->
j ∈ o -> consistent s ->
(forall k, st_obs (sm k) ≡ st_obs (s k)) ->
size o - 1 < size (st_obs (sm j)) ->
size (MuddyUnion s) - 1 = size o.
Proof.
intros Heqo Hin Hconsistent Hobs_equiv Hinvs.
destruct (Hconsistent) as [_ Hcons].
rewrite Heqo in *; clear o Heqo.
remember (size (st_obs (s i))) as o.
rewrite Hobs_equiv, Hcons, size_difference in Hinvs.
- rewrite size_singleton in Hinvs.
apply MC_number_of_muddy_seen with (n := i) in Hconsistent.
by destruct Hconsistent; lia.
- apply singleton_subseteq_l.
unfold MuddyUnion; rewrite elem_of_union_list.
exists (st_obs (s i)); split; [| done].
apply elem_of_list_fmap.
by exists i; split; [| apply elem_of_enum].
Qed.
Lemma MC_composite_invariant_preservation_muddy_from_clean (s sm : composite_state MCVLSM)
(i j : index) (o : indexSet) :
o ≡ st_obs (s i) -> j ∉ o -> consistent s ->
(forall k, st_obs (sm k) ≡ st_obs (s k)) ->
size o < size (st_obs (sm j)) ->
size (MuddyUnion s) - 1 = size o.
Proof.
intros Heqo Hin Hconsistent Hobs_equiv Hinvs.
destruct (Hconsistent) as [_ Hcons].
rewrite Heqo in *; clear o Heqo.
rewrite Hobs_equiv in Hinvs.
destruct (decide (i = j)); [by subst; lia |].
remember (size (st_obs (s i))) as o.
rewrite Hcons, size_difference_alt in Hinvs.
replace (size (MuddyUnion s ∩ {[j]})) with 0 in Hinvs.
- by apply MC_number_of_muddy_seen with (n := i) in Hconsistent; lia.
- symmetry; apply size_empty_iff.
by rewrite Hcons in Hin; set_solver.
Qed.
Lemma non_initial_state_has_init_tr (is s : composite_state MCVLSM)
(tr : list (composite_transition_item MCVLSM)) :
finite_valid_trace_init_to MC_composite_vlsm is s tr -> forall (i : index),
~ MC_initial_state_prop (s i) ->
exists (item : composite_transition_item MCVLSM), item ∈ tr /\ projT2 (l item) = init.
Proof.
intros Htr i Hnoninit.
induction Htr using finite_valid_trace_init_to_rev_ind;
[by contradiction Hnoninit; apply Hsi |].
destruct (decide (MC_initial_state_prop (s i))); cycle 1.
- destruct (IHHtr n) as (item & Hitem & Hinit).
by exists item; rewrite elem_of_app; itauto.
- eexists.
rewrite elem_of_app, elem_of_list_singleton.
split; [by right |]; cbn.
destruct Ht as [(_ & _ & Hv & _) Ht], l as (j & lj); cbn in Ht, Hv |- *.
destruct (MC_transition j lj (s j) iom) as [si' om'].
inversion Ht; subst; clear Ht.
destruct (decide (i = j)); subst; state_update_simpl; [| done].
unfold MC_initial_state_prop in m.
destruct (s j); cbn in *; subst.
by inversion Hv; subst.
Qed.
Lemma size_MuddyUnion_input_valid_transition :
forall (l : label MC_composite_vlsm) (s s' : composite_state MCVLSM) (iom oom : option Message),
input_valid_transition MC_composite_vlsm l (s, iom) (s', oom) ->
size (MuddyUnion s) = size (MuddyUnion s').
Proof.
intros * Hivt.
apply set_size_proper, MC_obs_equiv_preserves_muddy.
apply MC_trans_preserves_obs_equiv with l iom oom.
by apply Hivt.
Qed.
Lemma consistent_finite_valid_trace_from_to :
forall (s1 s2 : composite_state MCVLSM) (tr : list transition_item) (i : index),
finite_valid_trace_from_to MC_composite_vlsm s1 s2 tr ->
st_rs (s2 i) <> None ->
consistent s2.
Proof.
intros * Hfvt Hneq.
destruct (decide (composite_initial_state_prop MCVLSM s2)).
- by specialize (c i).
- apply MC_non_initial_valid_consistent.
split; [| done].
by apply valid_trace_last_pstate in Hfvt.
Qed.
Lemma consistent_valid_state_prop :
forall (s : composite_state MCVLSM) (i : index),
valid_state_prop MC_composite_vlsm s ->
st_rs (s i) <> None ->
consistent s.
Proof.
intros * Hv Hneq.
eapply consistent_finite_valid_trace_from_to; [| done].
by constructor.
Qed.
Lemma MC_component_invariant_helper_from_constraint :
forall (s : composite_state MCVLSM) (i : index) (r : nat) (status : ChildStatus),
MC_composite_invariant s ->
MC_constraint (existT i receive) (s, Some (mkMsg i r status)) ->
MC_component_invariant_helper (mkSt (st_obs (s i)) (Some (mkRS r status))) (MuddyUnion s).
Proof.
cbn; intros * Hinvs Hc.
destruct (s i) as [oj [[rj statusj] |]] eqn: Hsj; [| done].
destruct (Hinvs i) as [Hjinit | Hinvsj]; [by rewrite Hsj in Hjinit |].
unfold MC_component_invariant, MC_component_invariant_helper in Hinvsj.
rewrite Hsj in Hinvsj; cbn in Hinvsj |- *.
destruct Hc as [[] | []]; subst; [done |].
by destruct statusj; cbn; lia.
Qed.
(**
The proof of the following lemma proceeds by induction on the length of the trace
to the state [s] (such a trace exists because of the assumption that the state [s]
is valid). The induction step analyzes each case of the transition function
and proves the corresponding relations depending on the particular
conditions of the transition.
*)
Lemma MC_composite_invariant_preservation (s : composite_state MCVLSM) :
valid_state_prop MC_composite_vlsm s -> MC_composite_invariant s.
Proof.
intros Hvsp.
apply valid_state_has_trace in Hvsp as (is & tr & Htr).
remember (length tr) as len_tr.
revert s tr Heqlen_tr Htr.
induction len_tr as [len_tr Hind] using (well_founded_induction Wf_nat.lt_wf).
intros; subst len_tr.
destruct_list_last tr tr' lst Htr_lst;
destruct Htr as [Htr Hinit]; [by inversion Htr; subst; left |].
intros i.
apply finite_valid_trace_from_to_app_split in Htr as [Htr' Hlst].
remember (finite_trace_last is tr') as s'.
apply valid_trace_get_last in Hlst as Heqs.
apply valid_trace_forget_last, first_transition_valid in Hlst.
cbn in Heqs, Hlst; rewrite Heqs in Hlst.
destruct lst; cbn in *.
unfold MC_component_invariant, MC_component_invariant_helper.
erewrite <- size_MuddyUnion_input_valid_transition by done.
destruct l as [j lj], Hlst as [(_ & _ & Hv & Hc) Ht]; cbn in Ht.
destruct MC_transition eqn: Htj.
inversion Ht as [Hdest]; subst s o.
assert (Hinvs : MC_composite_invariant s').
{
eapply Hind; [| done..].
by rewrite app_length; cbn; lia.
}
destruct (decide (j = i)); [subst j |]; state_update_simpl; [| by apply (Hinvs i)].
clear - Htr' Hinit Hdest Hv Hc Htj Hinvs Hind.
right.
pose proof (Hinvs' := Hinvs).
specialize (Hinvs i).
funelim (MC_transition i lj (s' i) input);
inversion Hv; try congruence;
rewrite <- H10 in H0; inversion H0; subst; clear H0; rewrite Htj in Heqcall.
- (* emit *)
inversion Heqcall; subst; cbn in *; clear Heqcall Htj.
unfold MC_component_invariant in Hinvs; rewrite <- H10 in Hinvs; cbn in Hinvs.
by destruct Hinvs.
- (* receive *)
inversion Heqcall; subst; cbn in *; clear Heqcall Htj.
unfold MC_component_invariant in Hinvs; rewrite <- H10 in Hinvs; cbn in Hinvs.
by destruct Hinvs.
- (* receive *)
inversion Heqcall; subst; cbn in *; clear Heqcall Htj.
unfold MC_component_invariant in Hinvs; rewrite <- H10 in Hinvs; cbn in Hinvs.
by destruct Hinvs.
- (* init *)
inversion Heqcall; subst; cbn in *; clear Heqcall Htj Hinvs.
split; [done |].
destruct Hc as [Hunion Hc].
specialize (Hc i); rewrite <- H10 in Hc.
cbn in Hc; rewrite Hc, size_difference, size_singleton; [done |].
apply singleton_subseteq_l.
by apply size_empty_iff in Heq; rewrite Heq in Hc; set_solver.
- (* init *)
by inversion Heqcall; subst; cbn in *; lia.
- (* receive *)
unfold MC_component_invariant in Hinvs; rewrite <- H10 in Hinvs; cbn in Hinvs.
destruct Hinvs; [done |].
eapply consistent_finite_valid_trace_from_to in Htr'
as [HMuddy_s' Hconsistent]; [| by rewrite <- H10; cbn].
specialize (Hconsistent i) as Hconsi.
rewrite <- H10 in Hconsi; cbn in Hconsi.
assert (Hinvs : MC_component_invariant_helper (mkSt (st_obs (s' j))
(Some (mkRS r' undecided))) (MuddyUnion s'))
by (eapply MC_component_invariant_helper_from_constraint; done).
assert (o0 ≡ st_obs (s' i)) by (rewrite <- H10; done).
repeat case_decide; inversion Heqcall; subst; cbn in *; clear Heqcall;
repeat split; try lia; [| done].
by eapply MC_composite_invariant_preservation_muddy_from_undecided.
- (* receive *)
unfold MC_component_invariant in Hinvs; rewrite <- H10 in Hinvs; cbn in Hinvs.
destruct Hinvs; [done |].
eapply consistent_finite_valid_trace_from_to in Htr'
as [HMuddy_s' Hconsistent]; [| by rewrite <- H10; cbn].
specialize (Hconsistent i) as Hconsi.
rewrite <- H10 in Hconsi; cbn in Hconsi.
assert (Hinvs : MC_component_invariant_helper (mkSt (st_obs (s' j))
(Some (mkRS r' undecided))) (MuddyUnion s'))
by (eapply MC_component_invariant_helper_from_constraint; done).
assert (o0 ≡ st_obs (s' i)) by (rewrite <- H10; done).
repeat case_decide; inversion Heqcall; subst; cbn in *; clear Heqcall;
repeat split; try lia; [done |].
by eapply MC_composite_invariant_preservation_muddy_from_clean.
- (* receive *)
unfold MC_component_invariant in Hinvs; rewrite <- H10 in Hinvs; cbn in Hinvs.
destruct Hinvs; [done |].
eapply consistent_finite_valid_trace_from_to in Htr'
as [HMuddy_s' Hconsistent]; [| by rewrite <- H10; cbn].
specialize (Hconsistent i) as Hconsi.
rewrite <- H10 in Hconsi; cbn in Hconsi.
assert (Hinvs : MC_component_invariant_helper (mkSt (st_obs (s' j))
(Some (mkRS r' muddy))) (MuddyUnion s'))
by (eapply MC_component_invariant_helper_from_constraint; done).
assert (o0 ≡ st_obs (s' i)) by (rewrite <- H10; done).
repeat case_decide; inversion Heqcall; subst; cbn in *; clear Heqcall;
repeat split; try lia; [| done].
destruct Hinvs as [Hstobs Hmuddy].
rewrite <- Hmuddy in Hstobs.
destruct (decide (size (MuddyUnion s') = 0)); [| by lia].
by apply size_non_empty_iff in HMuddy_s'.
- (* receive *)
inversion Heqcall; subst; cbn in *; clear Heqcall Htj.
unfold MC_component_invariant in Hinvs; rewrite <- H10 in Hinvs; cbn in Hinvs.
by destruct Hinvs.
- (* receive *)
inversion Heqcall; cbn in *; subst; clear Heqcall Htj.
unfold MC_component_invariant in Hinvs; rewrite <- H10 in Hinvs; cbn in Hinvs.
by destruct Hinvs.
- (* receive *)
unfold MC_component_invariant in Hinvs; rewrite <- H10 in Hinvs; cbn in Hinvs.
destruct Hinvs; [done |].
eapply consistent_finite_valid_trace_from_to in Htr'
as [HMuddy_s' Hconsistent]; [| by rewrite <- H10; cbn].
specialize (Hconsistent i) as Hconsi.
rewrite <- H10 in Hconsi; cbn in Hconsi.
assert (Hinvs : MC_component_invariant_helper (mkSt (st_obs (s' j))
(Some (mkRS r' clean))) (MuddyUnion s'))
by (eapply MC_component_invariant_helper_from_constraint; done).
assert (o0 ≡ st_obs (s' i)) by (rewrite <- H10; done).
by repeat case_decide; inversion Heqcall; subst; cbn in *; clear Heqcall; lia.
Qed.
Lemma MC_composite_invariant_preservation_inductive (s : composite_state MCVLSM) :
valid_state_prop MC_composite_vlsm s -> MC_composite_invariant_inductive s.
Proof.
intros Hv i.
destruct (MC_composite_invariant_preservation _ Hv i); [by left|].
by right; apply MC_component_invariant_equiv_MC_component_invariant_inductive.
Qed.
(** ** Auxiliary progress results *)
Lemma MC_valid_noequiv_muddy (s : composite_state MCVLSM) (m : Message) :
valid_state_prop MC_composite_vlsm s ->
msg_status m = muddy ->
MC_no_equivocation s m ->
msg_round m = size (MuddyUnion s) - 1 /\ msg_index m ∈ MuddyUnion s.
Proof.
intros Hs Hmuddy Hnoequiv.
pose proof (Hs' := Hs).
apply MC_composite_invariant_preservation in Hs.
destruct (Hs (msg_index m)) as [Hinit | Hinvariant].
- unfold MC_no_equivocation in Hnoequiv.
repeat case_match; cbn in *; [| done].
unfold MC_initial_state_prop in Hinit.
by rewrite H10 in Hinit.
- unfold MC_component_invariant, MC_component_invariant_helper in Hinvariant.
unfold MC_no_equivocation in Hnoequiv.
repeat case_match; cbn in *; subst; try done;
destruct Hnoequiv as [[Hnoequivst Hnoequivr] | [Hnoequivst Hnoequivr]];
subst; rewrite H11 in H9; cbn in *; try done.
rewrite H11 in Hinvariant; cbn in Hinvariant.
destruct Hinvariant as [Hn Hstobs].
split; [by rewrite <- Hstobs in Hn |].
eapply consistent_valid_state_prop in Hs' as [Hnempty Hcons];
[| by rewrite H11; cbn].
replace st_obs0 with (st_obs (s msg_index0)) in Hstobs; [| by rewrite H11].
rewrite Hcons, size_difference_alt in Hstobs.
apply size_non_empty_iff in Hnempty.
assert (Hintersectgeq1 : size (MuddyUnion s ∩ {[msg_index0]}) >= 1) by lia.
assert (Hintersectleq1 : MuddyUnion s ∩ {[msg_index0]} ⊆ {[msg_index0]}) by set_solver.
apply subseteq_size in Hintersectleq1.
rewrite size_singleton in Hintersectleq1.
assert (Hintersecteq1 : size (MuddyUnion s ∩ {[msg_index0]}) = 1) by lia.
apply size_1_elem_of in Hintersecteq1.
by set_solver.
Qed.
Lemma MC_valid_noninitial_state_undecided_round_less_obs
(s : composite_state MCVLSM) (i : index) :
valid_state_prop MC_composite_vlsm s ->
~ MC_initial_state_prop (s i) ->
state_status (st_rs (s i)) = undecided ->
state_round (st_rs (s i)) < size (st_obs (s i)).
Proof.
intros Hvalid Hundecided.
apply MC_composite_invariant_preservation_inductive in Hvalid.
destruct (Hvalid i); [done |].
by inversion H9; [| congruence ..].