-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBasicRubik.v
2850 lines (2630 loc) · 110 KB
/
BasicRubik.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
Require Import ZArith.
Require Import List.
(*****************************************************************************)
(* *)
(* Some Properties of fold_left *)
(* *)
(*****************************************************************************)
Lemma fold_left_cons (A B : Type) (f : A -> B -> A)
(b : B) (l : list B) (i : A) :
fold_left f (b :: l) i = fold_left f l (f i b).
Proof. trivial. Qed.
Lemma fold_right_cons (A B : Type) (f : B -> A -> A)
(b : B) (l : list B) (i : A) :
fold_right f i (b :: l) = f b (fold_right f i l).
Proof. trivial. Qed.
Lemma fold_left_comb (A B C D : Type) (f : B -> C -> D) (g : A -> D -> A)
(l1 : list C) (l2 : list B) (i : A) :
fold_left (fun x y =>
fold_left (fun x1 y1 => g x1 (f y y1)) l1 x) l2 i =
fold_left g (fold_right (fun y x => (map (f y) l1)++x) nil l2) i .
Proof.
revert i; elim l2; simpl; auto; clear l2.
intros b l2 Hrec i.
rewrite Hrec.
rewrite fold_left_app.
apply f_equal2 with (f := fold_left g); auto.
generalize i; elim l1; simpl; auto; clear l1 Hrec.
Qed.
(*****************************************************************************)
(* *)
(* Permutations *)
(* *)
(*****************************************************************************)
Inductive perm {A : Type} : list A -> list A -> Prop :=
perm_id: forall l, perm l l
| perm_swap: forall a b l,
perm (a :: b :: l) (b :: a :: l)
| perm_skip: forall a l1 l2,
perm l1 l2 -> perm (a :: l1) (a :: l2)
| perm_trans: forall l1 l2 l3,
perm l1 l2 -> perm l2 l3 -> perm l1 l3.
(*****************************************************************************)
(* *)
(* Uniqueness *)
(* *)
(*****************************************************************************)
Inductive unique {A: Type} : list A -> Prop :=
uniqN: unique nil
| uniqC: forall (a : A) l,
unique l -> ~ In a l -> unique (a :: l).
Lemma unique_inv (A : Type) (a : A) l : unique (a:: l) -> unique l.
Proof. intro H; inversion H; auto. Qed.
Lemma unique_app (A: Type) (l1 l2: list A) : unique (l1 ++ l2) -> unique l1.
Proof.
elim l1; clear l1.
- intros; apply uniqN.
- intros a l1 Hrec H; inversion_clear H as [| xx yy Ha Hb].
apply uniqC; auto with datatypes.
Qed.
Lemma unique_perm (A : Type) (l1 l2 : list A) :
perm l1 l2 -> unique l1 -> unique l2.
Proof.
intro H; elim H; clear l1 l2 H; auto.
- intros a b l H; inversion_clear H as [| xx yy Ha Hb].
inversion_clear Ha as [| xx uu Ha1 Hb1].
repeat apply uniqC; auto with datatypes.
simpl; intros [H1 | H1]; subst; auto with datatypes.
- intros a l1 l2 H1 H2 H3.
inversion_clear H3 as [| xx yy Ha Hb].
apply uniqC; auto with datatypes.
contradict Hb; generalize Hb; elim H1; clear l1 l2 H1 H2 Ha Hb;
auto with datatypes.
* simpl; intros a1 b1 l [H1 | [H1 | H1]]; auto.
* simpl; intros a1 l1 l2 H Hrec [H1 | H1]; auto.
Qed.
(*****************************************************************************)
(* *)
(* Equality test for positive *)
(* *)
(*****************************************************************************)
Fixpoint positive_eq (p1 p2 : positive) {struct p1} : bool :=
match p1, p2 with
xH, xH => true
| xO p3, xO p4 => positive_eq p3 p4
| xI p3, xI p4 => positive_eq p3 p4
| _, _ => false
end.
Lemma positive_eq_correct p1 p2 :
if positive_eq p1 p2 then p1 = p2 else p1 <> p2.
Proof.
revert p2; elim p1; [intros p3 Hrec | intros p3 Hrec|];
intros p2; (case p2; [intros p4 | intros p4 |]); simpl;
try (intros HH; discriminate HH); auto; generalize (Hrec p4);
case positive_eq; intros HH; try (subst p3; auto; fail);
intros HH1; case HH; injection HH1; auto.
Qed.
(*****************************************************************************)
(* *)
(* Some modulo-3 operations for positive *)
(* *)
(*****************************************************************************)
Definition pos_up x :=
match x with
| 1%positive => 2%positive
| 2%positive => 3%positive
| _ => 1%positive
end.
Definition pos_down x :=
match x with
| 2%positive => 1%positive
| 3%positive => 2%positive
| _ => 3%positive
end.
Lemma pos_up_less_4 s : (pos_up s < 4)%positive.
Proof.
case s; simpl; try (intros; red; simpl; auto; fail).
intros p; case p; simpl; try (intros; red; simpl; auto; fail).
Qed.
Lemma pos_up_mod_3 s : (s < 4)%positive ->
(Z.pred (Zpos (pos_up s)) mod 3 = (1 + Z.pred (Z.pos s)) mod 3)%Z.
Proof.
case s; simpl; auto; intros p; case p; simpl; auto;
intros p1; case p1; unfold Pos.lt; intros; discriminate.
Qed.
Lemma pos_down_less_4 s : (pos_down s < 4)%positive.
Proof.
case s; simpl; try (intros; red; simpl; auto; fail).
- intros p; case p; simpl; try (intros; red; simpl; auto; fail).
- intros p; case p; simpl; try (intros; red; simpl; auto; fail).
Qed.
Lemma pos_down_mod_3 s : (s < 4)%positive ->
(Z.pred (Zpos (pos_down s)) mod 3 = (2 + Z.pred (Zpos s)) mod 3)%Z.
Proof.
case s; simpl; auto; intros p; case p; simpl; auto;
intros p1; case p1; unfold Pos.lt; intros; discriminate.
Qed.
Lemma pos_down_up s : (s < 4 -> pos_down (pos_up s) = s)%positive.
Proof.
case s; simpl; auto; intros p; case p; simpl; auto;
intros p1; case p1; auto; intros; discriminate.
Qed.
(*****************************************************************************)
(* *)
(* The seven cubes *)
(* *)
(*****************************************************************************)
Inductive cube := C1 | C2 | C3 | C4 | C5 | C6 | C7.
Lemma unique7: unique (C1 :: C2 :: C3 :: C4 :: C5 :: C6 :: C7 :: nil).
Proof.
repeat apply uniqC; try apply uniqN; auto with datatypes;
simpl; intuition; discriminate.
Qed.
Definition c2N e := match e with
C1 => 0 | C2 => 1 | C3 => 2 | C4 => 3 | C5 => 4 | C6 => 5 | C7 => 6
end.
Definition N2c n := match n with
0 => C1 | 1 => C2 | 2 => C3 | 3 => C4 | 4 => C5 | 5 => C6 | _ => C7
end.
Definition dummy {S1 : Type} (S2 : Type) (e : S1) := S2.
Definition cube_pred_aux (c : cube) : cube.
change cube with (dummy cube c).
case c; match goal with |- dummy _ ?n =>
let e := eval compute in (N2c (pred (c2N n))) in
exact e
end.
Defined.
Definition cube_pred (c : cube) :=
Eval lazy in cube_pred_aux c.
Definition cube_succ_aux (c : cube) : dummy cube c.
case c; match goal with |- dummy _ ?n =>
let e := eval compute in (N2c (S (c2N n))) in
exact e
end.
Defined.
Definition cube_succ c := Eval lazy in cube_succ_aux c.
Definition cube_compare_aux (c1 c2 : cube) : dummy comparison (c1,c2).
case c1; case c2; match goal with |- dummy _ (?n1,?n2) =>
let e := eval compute in (Nat.compare (c2N n1) (c2N n2)) in
exact e
end.
Defined.
Definition cube_compare (c1 c2 : cube) := Eval lazy in cube_compare_aux c1 c2.
Lemma cube_compare_correct c1 c2 :
match cube_compare c1 c2 with
| Eq => c1 = c2
| Lt => (c2N c1 < c2N c2)%nat
| Gt => (c2N c1 > c2N c2)%nat
end.
Proof. case c1; case c2; simpl; auto with arith. Qed.
Definition cube_encode_aux (c1 c2 : cube) : dummy positive (c1, c2).
case c1; case c2; match goal with |- dummy _ (?n1,?n2) =>
let e := eval compute in (P_of_succ_nat (5 * c2N n2 + c2N n1)) in
exact e
end.
Defined.
Definition cube_encode (c1 c2 : cube) :=
Eval lazy in cube_encode_aux c1 c2.
Definition cube_decode_aux (p: positive) : dummy (cube * cube) p.
revert p.
do 5 try (intro p; case p; clear p); try (intros p; exact (C1 , C1));
match goal with |- dummy _ ?n =>
let z1 := eval compute in ((Zpos n - 1) mod 5)%Z in
let z2 := eval compute in ((Zpos n - 1) / 5)%Z in
let e := eval compute in (N2c (Z.abs_nat z1), N2c (Z.abs_nat z2)) in
exact e
end.
Defined.
Definition cube_decode (p: positive) :=
Eval lazy in cube_decode_aux p.
Lemma cube_encode_decode c1 c2 :
c2N c1 - 4 = 0 -> c2N c2 - 5 = 0 -> cube_decode (cube_encode c1 c2) = (c1, c2).
Proof.
case c1; case c2; simpl; auto; intros; try discriminate.
Qed.
Definition cube_eq c1 c2 :=
match cube_compare c1 c2 with Eq => true | _ => false end.
Lemma cube_eq_correct c1 c2 : if cube_eq c1 c2 then c1 = c2 else c1 <> c2.
Proof.
case c1; case c2; simpl; auto; intros; discriminate.
Qed.
(*****************************************************************************)
(* *)
(* The 3 Orientations *)
(* *)
(*****************************************************************************)
Inductive orientation := O1 | O2 | O3.
Definition o2N e := match e with
O1 => 0 | O2 => 1 | O3 => 2
end.
Definition N2o n := match n with
0 => O1 | 1 => O2 | _ => O3
end.
Definition oup o := match o with O1 => O2 | O2 => O3 | O3 => O1 end.
Definition odown o := match o with O1 => O3 | O2 => O1 | O3 => O2 end.
Definition oinv o := match o with O1 => O1 | O2 => O3 | O3 => O2 end.
Definition oadd o1 o2 := match o1 with O1 => o2 | O2 => oup o2 | O3 => odown o2 end.
Definition o2Z o := match o with O1 => 0%Z | O2 => 1%Z | O3 => 2%Z end.
Definition oeq o1 o2 :=
match o1, o2 with
| O1, O1 => true
| O2, O2 => true
| O3, O3 => true
| _, _ => false
end.
Lemma oeq_correct o1 o2 :
if oeq o1 o2 then o1 = o2 else o1 <> o2.
Proof.
case o1; case o2; simpl; auto; intros; discriminate.
Qed.
Lemma oup_mod_3 o : (o2Z (oup o) mod 3 = (o2Z o + 1) mod 3)%Z.
Proof.
case o; simpl; auto.
Qed.
Lemma odown_mod_3 o : (o2Z (odown o) mod 3 = (o2Z o - 1) mod 3)%Z.
Proof.
case o; simpl; auto.
Qed.
Lemma oadd_mod_3 ox oy :
(o2Z (oadd ox oy) mod 3 = (o2Z ox mod 3 + o2Z oy mod 3) mod 3)%Z.
Proof.
case ox; case oy; simpl; auto.
Qed.
Lemma oinv_eq ox oy : oadd ox oy = O1 -> oinv ox = oy.
Proof.
case ox; case oy; simpl; auto; intros; discriminate.
Qed.
Lemma eq_mod_3 ox oy : (o2Z ox mod 3 = o2Z oy mod 3)%Z -> ox = oy.
Proof.
case ox; case oy; simpl; auto; intros; discriminate.
Qed.
Lemma oup_down o : oup (odown o) = o.
Proof. case o; simpl; auto. Qed.
Lemma odown_up o : odown (oup o) = o.
Proof. case o; simpl; auto. Qed.
Definition cube3_encode_aux (o : orientation) (c1 c2 : cube) :
dummy positive (o, c1, c2).
case o; case c1; case c2; match goal with |- dummy _ (?n0, ?n1,?n2) =>
let e := eval compute in (P_of_succ_nat (21 * o2N n0 + 7 * c2N n1 + c2N n2)) in
exact e
end.
Defined.
Definition cube3_encode o c1 c2 := Eval lazy in cube3_encode_aux o c1 c2.
Definition cube3_decode_aux (p: positive) : dummy (orientation * cube * cube) p.
revert p.
do 6 try (intros p; case p; clear p); try (intros p; exact (O1, C1 , C1));
match goal with |- dummy _ ?n =>
exact (
let z1 := ((Zpos n - 1) mod 7)%Z in
let z2 := ((Zpos n - 1) / 7)%Z in
let z3 := (z2 mod 3)%Z in
let z4 := (z2 / 3)%Z in
(N2o (Z.abs_nat z4), N2c (Z.abs_nat z3), N2c (Z.abs_nat z1)))
end.
Defined.
Definition cube3_decode p := Eval lazy in cube3_decode_aux p.
Lemma cube3_encode_decode o c1 c2 :
o2N o - 2 = 0 -> c2N c1 - 2 = 0 ->
cube3_decode (cube3_encode o c1 c2) = (o, c1, c2).
Proof.
case o; case c1; case c2; simpl; auto; intros; try discriminate.
Qed.
(*****************************************************************************)
(* *)
(* State *)
(* *)
(*****************************************************************************)
Inductive state :=
State (c1 c2 c3 c4 c5 c6 c7 : cube)
(o1 o2 o3 o4 o5 o6 o7 : orientation).
Definition init_state := State C1 C2 C3 C4 C5 C6 C7 O1 O1 O1 O1 O1 O1 O1.
Definition valid_state s :=
match s with
| State c1 c2 c3 c4 c5 c6 c7 o1 o2 o3 o4 o5 o6 o7 =>
perm (C1 :: C2 :: C3 :: C4 :: C5 :: C6 :: C7 :: nil)
(c1 :: c2 :: c3 :: c4 :: c5 :: c6 :: c7 :: nil) /\
fold_left oadd
(o1 :: o2 :: o3 :: o4 :: o5 :: o6 :: o7 :: nil) O1 = O1
end.
Lemma valid_state_init : valid_state init_state.
Proof.
simpl; repeat split; auto.
apply perm_id.
Qed.
Definition state_eq (s1 s2: state) :=
match s1, s2 with
State p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14,
State q1 q2 q3 q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 =>
(cube_eq p1 q1 && cube_eq p2 q2 && cube_eq p3 q3 &&
cube_eq p4 q4 && cube_eq p5 q5 && cube_eq p6 q6 && cube_eq p7 q7 &&
oeq p8 q8 && oeq p9 q9 && oeq p10 q10 && oeq p11 q11 &&
oeq p12 q12 && oeq p13 q13 && oeq p14 q14)%bool
end.
Lemma state_eq_correct s1 s2 :
if state_eq s1 s2 then s1 = s2 else s1 <> s2.
Proof.
case s1; case s2; intros; unfold state_eq.
repeat match goal with |- context[cube_eq ?X ?Y] =>
generalize (cube_eq_correct X Y); case cube_eq;
[idtac | intros HH HH1; case HH; injection HH1; auto];
intros; subst Y
end; simpl; auto.
repeat match goal with |- context[oeq ?X ?Y] =>
generalize (oeq_correct X Y); case oeq;
[idtac | intros HH HH1; case HH; injection HH1; auto];
intros; subst Y
end; simpl; auto.
Qed.
Local Definition states := list state.
Fixpoint in_states s (ls : states) {struct ls} : bool :=
match ls with
| nil => false
| cons s1 ls1 => if state_eq s s1 then true else in_states s ls1
end.
Lemma in_states_correct s ls :
if in_states s ls then In s ls else ~In s ls.
Proof.
elim ls; simpl; auto.
intros a l1 Hrec; generalize (state_eq_correct s a); case state_eq; auto.
intros H1; generalize Hrec; case in_states; auto.
intros HH [HH1 | HH1]; case H1; auto; case HH; auto.
Qed.
(*****************************************************************************)
(* *)
(* Rotations *)
(* *)
(*****************************************************************************)
(** Right Rotation: 1 -(-1)-> 4 -(+1)-> 5 -(-1)-> 2 -(+1)-> 1 **)
Definition rright s :=
match s with
| State p1 p2 p3 p4 p5 p6 p7 o1 o2 o3 o4 o5 o6 o7 =>
State p2 p5 p3 p1 p4 p6 p7 (oup o2) (odown o5) o3 (odown o1) (oup o4) o6 o7
end.
Eval compute in rright init_state.
(** Back Rotation: 4 -(-1)-> 7 -(+1)-> 6 -(-1)-> 5 -(+1)-> 4 **)
Definition rback s :=
match s with
| State p1 p2 p3 p4 p5 p6 p7 o1 o2 o3 o4 o5 o6 o7 =>
State p1 p2 p3 p5 p6 p7 p4 o1 o2 o3 (oup o5) (odown o6) (oup o7) (odown o4)
end.
Eval compute in rback init_state.
(** Down Rotation: 2 -(+0)-> 5 -(+0)-> 6 -(+0)-> 3 -(+0)-> 2 **)
Definition rdown s :=
match s with
| State p1 p2 p3 p4 p5 p6 p7 o1 o2 o3 o4 o5 o6 o7 =>
State p1 p3 p6 p4 p2 p5 p7 o1 o3 o6 o4 o2 o5 o7
end.
Eval compute in rdown init_state.
Ltac Zmod_plus_tac H :=
match H with
| ((?X mod 3 + ?Y mod 3) mod 3)%Z =>
let X1 := constr:((X mod 3)%Z) in
let Y1 := constr:((Y mod 3)%Z) in
Zmod_plus_tac X1 || Zmod_plus_tac Y1 || rewrite <- (Zplus_mod X Y 3)
| _ => idtac
end.
Lemma valid_state_right s : valid_state s -> valid_state (rright s).
Proof.
case s; unfold valid_state, rright, fold_left;
intros p1 p2 p3 p4 p5 p6 p7 o1 o2 o3 o4 o5 o6 o7 (H1, H2).
split.
- apply perm_trans with (1 := H1).
refine (perm_trans _ _ _ (perm_swap _ _ _) _).
apply perm_skip.
refine (perm_trans _ _ _ (perm_swap _ _ _) _).
refine (perm_trans _ _ _ _ (perm_swap _ _ _)).
apply perm_skip.
refine (perm_trans _ _ _ _ (perm_swap _ _ _)).
apply perm_skip.
refine (perm_trans _ _ _ _ (perm_swap _ _ _)).
apply perm_id.
- apply trans_equal with (2 := H2).
apply eq_mod_3; auto; try (red; auto; fail).
repeat rewrite oadd_mod_3 || rewrite oup_mod_3 || rewrite odown_mod_3.
simpl.
repeat rewrite Zmod_mod.
do 7 match goal with |- ?X = _ => Zmod_plus_tac X end.
do 7 match goal with |- _ = ?X => Zmod_plus_tac X end.
apply f_equal2 with (f := BinIntDef.Z.modulo); auto.
ring.
Qed.
Lemma valid_state_back s : valid_state s -> valid_state (rback s).
Proof.
case s; unfold valid_state, rright, fold_left;
intros p1 p2 p3 p4 p5 p6 p7 o1 o2 o3 o4 o5 o6 o7 (H1, H2).
split.
- apply perm_trans with (1 := H1).
do 3 apply perm_skip.
refine (perm_trans _ _ _ (perm_swap _ _ _) _).
apply perm_skip.
refine (perm_trans _ _ _ (perm_swap _ _ _) _).
apply perm_skip.
refine (perm_trans _ _ _ (perm_swap _ _ _) _).
apply perm_id.
- apply trans_equal with (2 := H2).
apply eq_mod_3; auto; try (red; auto; fail).
repeat rewrite oadd_mod_3 || rewrite oup_mod_3 || rewrite odown_mod_3.
simpl.
repeat rewrite Zmod_mod.
do 7 match goal with |- ?X = _ => Zmod_plus_tac X end.
do 7 match goal with |- _ = ?X => Zmod_plus_tac X end.
apply f_equal2 with (f := BinIntDef.Z.modulo); auto.
ring.
Qed.
Lemma valid_state_down s : valid_state s -> valid_state (rdown s).
Proof.
case s; unfold valid_state, rright, fold_left;
intros p1 p2 p3 p4 p5 p6 p7 o1 o2 o3 o4 o5 o6 o7 (H1, H2).
split.
- apply perm_trans with (1 := H1).
apply perm_skip.
refine (perm_trans _ _ _ (perm_swap _ _ _) _).
apply perm_skip.
refine (perm_trans _ _ _ _ (perm_swap _ _ _)).
refine (perm_trans _ _ _ (perm_swap _ _ _) _).
apply perm_skip.
refine (perm_trans _ _ _ _ (perm_swap _ _ _)).
apply perm_skip.
refine (perm_trans _ _ _ _ (perm_swap _ _ _)).
apply perm_id.
- apply trans_equal with (2 := H2).
apply eq_mod_3; auto; try (red; auto; fail).
repeat rewrite oadd_mod_3 || rewrite oup_mod_3 || rewrite odown_mod_3.
simpl.
repeat rewrite Zmod_mod.
do 7 match goal with |- ?X = _ => Zmod_plus_tac X end.
do 7 match goal with |- _ = ?X => Zmod_plus_tac X end.
apply f_equal2 with (f := BinIntDef.Z.modulo); auto.
ring.
Qed.
Lemma right_4 s : rright (rright (rright (rright s))) = s.
Proof.
case s; simpl; intros.
repeat rewrite oup_down; repeat rewrite odown_up; auto.
Qed.
Lemma back_4 s : rback (rback (rback (rback s))) = s.
Proof.
case s; simpl; intros.
repeat rewrite oup_down; repeat rewrite odown_up; auto.
Qed.
Lemma down_4 s : rdown (rdown (rdown (rdown s))) = s.
Proof.
case s; simpl; intros.
repeat rewrite oup_down; repeat rewrite odown_up; auto.
Qed.
(*****************************************************************************)
(* *)
(* Reachability *)
(* *)
(*****************************************************************************)
Inductive reachable : state -> Prop :=
reach0: reachable init_state
| reachr: forall s, reachable s -> reachable (rright s)
| reachb: forall s, reachable s -> reachable (rback s)
| reachd: forall s, reachable s -> reachable (rdown s).
Lemma reachable_valid s : reachable s -> valid_state s.
Proof.
intros H; elim H; auto.
- apply valid_state_init.
- intros; apply valid_state_right; auto.
- intros; apply valid_state_back; auto.
- intros; apply valid_state_down; auto.
Qed.
Definition move (s1 s2 : state) :=
s2 = rright s1 \/
s2 = rright (rright s1) \/
s2 = rright (rright (rright s1)) \/
s2 = rback s1 \/
s2 = rback (rback s1) \/
s2 = rback (rback (rback s1)) \/
s2 = rdown s1 \/
s2 = rdown (rdown s1) \/
s2 = rdown (rdown (rdown s1)).
Lemma move_valid s1 s2 : valid_state s1 -> move s1 s2 -> valid_state s2.
Proof.
intros Hg [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | H1]]]]]]]];
subst s2; repeat (apply valid_state_right || apply valid_state_back
|| apply valid_state_down; auto).
Qed.
Lemma move_sym s1 s2 : valid_state s1 -> move s1 s2 -> move s2 s1.
Proof.
intros Hg [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | H1]]]]]]]];
subst s2;
try (pattern s1 at 2; rewrite <- right_4; unfold move; auto; fail);
try (pattern s1 at 2; rewrite <- down_4; auto; unfold move; do 6 right; auto; fail);
pattern s1 at 2; rewrite <- back_4; auto; unfold move; do 3 right; auto.
Qed.
Inductive nreachable: nat -> state -> Prop :=
| nreach0: nreachable 0 init_state
| nreachS: forall n s1 s2,
nreachable n s1 -> move s1 s2 -> nreachable (S n) s2.
Lemma nreachable_reachable n s : nreachable n s -> reachable s.
Proof.
intros H; elim H; clear n s H; intros; auto.
apply reach0.
generalize H1; clear H1;
intros [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | H1]]]]]]]];
subst s2; repeat apply reachr; repeat apply reachb;
repeat apply reachd; auto.
Qed.
Lemma reachable_nreachable s : reachable s -> exists n, nreachable n s.
Proof.
intros H; elim H; clear s H; try (exists 0%nat; apply nreach0);
intros s Hs (n, Hrec); exists (S n); apply nreachS with s; auto;
unfold move; auto; do 6 right; auto.
Qed.
Lemma move_nreachable n s2 :
nreachable (S n) s2 -> exists s1, move s1 s2 /\ nreachable n s1.
Proof.
intros H; inversion_clear H as [| xx s1 yy Hs1 Hs2];
exists s1; auto.
Qed.
Lemma nreachable_valid n s : nreachable n s -> valid_state s.
Proof.
intros H; elim H; clear n s H.
apply valid_state_init.
intros n s1 s2 H1 H2 H3; apply move_valid with s1; auto.
Qed.
Definition nreachable_dec n s :
valid_state s -> {nreachable n s} + {~nreachable n s}.
Proof.
revert s; elim n; simpl; auto.
- intros s; generalize (state_eq_correct s init_state); case state_eq; intros HH.
* left; rewrite HH; apply nreach0.
* right; intros HH1; case HH; inversion_clear HH1; auto.
- intros n1 Hrec s Hg.
case (Hrec (rright s)); try intros H1.
* apply valid_state_right; auto.
* left; rewrite <- right_4; try apply nreachr3; auto.
apply nreachS with (1 := H1); unfold move; auto.
* case (Hrec (rright (rright s))); try intros H2.
+ repeat apply valid_state_right; auto.
+ left; rewrite <- right_4; try apply nreachr2; auto.
apply nreachS with (1 := H2); unfold move; auto.
+ case (Hrec (rright (rright (rright s)))); try intros H3.
-- repeat apply valid_state_right; auto.
-- left; rewrite <- right_4; try apply nreachr1; auto.
apply nreachS with (1 := H3); unfold move; auto.
-- case (Hrec (rback s)); try intros H4.
** apply valid_state_back; auto.
** left; rewrite <- back_4; try apply nreachb3; auto.
apply nreachS with (1 := H4); unfold move; do 3 right; auto.
** case (Hrec (rback (rback s))); try intros H5.
++ repeat apply valid_state_back; auto.
++ left; rewrite <- back_4; try apply nreachb2; auto.
apply nreachS with (1 := H5); unfold move; do 3 right; auto.
++ case (Hrec (rback (rback (rback s)))); try intros H6.
--- repeat apply valid_state_back; auto.
--- left; rewrite <- back_4; try apply nreachb1; auto.
apply nreachS with (1 := H6); unfold move; do 3 right; auto.
--- case (Hrec (rdown s)); try intros H7.
*** apply valid_state_down; auto.
*** left; rewrite <- down_4; try apply nreachd3; auto.
apply nreachS with (1 := H7); unfold move;
do 6 right; auto.
*** case (Hrec (rdown (rdown s))); try intros H8.
++++ repeat apply valid_state_down; auto.
++++ left; rewrite <- down_4; try apply nreachd2; auto.
apply nreachS with (1 := H8);
unfold move; do 6 right; auto.
++++ case (Hrec (rdown (rdown (rdown s)))); try intros H9.
---- repeat apply valid_state_down; auto.
---- left; rewrite <- down_4;
try apply nreachd1; auto.
apply nreachS with (1 := H9);
unfold move; do 6 right; auto.
---- right; intros H10.
case (move_nreachable _ _ H10);
intros s1 HH; case HH; clear HH.
intros [HH1 | [HH1 | [HH1 | [HH1 | [HH1 |
[HH1 | [HH1 | [HH1 | HH1]]]]]]]] HH2;
subst s.
**** case H3; rewrite right_4; auto;
apply nreachable_valid with n1; auto.
**** case H2; rewrite right_4; auto;
apply nreachable_valid with n1; auto.
**** case H1; rewrite right_4; auto;
apply nreachable_valid with n1; auto.
**** case H6; rewrite back_4; auto;
apply nreachable_valid with n1; auto.
**** case H5; rewrite back_4; auto;
apply nreachable_valid with n1; auto.
**** case H4; rewrite back_4; auto;
apply nreachable_valid with n1; auto.
**** case H9; rewrite down_4; auto;
apply nreachable_valid with n1; auto.
**** case H8; rewrite down_4; auto;
apply nreachable_valid with n1; auto.
**** case H7; rewrite down_4; auto;
apply nreachable_valid with n1; auto.
Qed.
Definition nreachable_le_dec n s :
valid_state s ->
{forall m, m < n -> ~ nreachable m s} + {exists m, m < n /\ nreachable m s}.
Proof.
intro Hs; elim n; simpl; clear n.
- left; intros m Hm; contradict Hm; auto with arith.
- intros n [Hrec | Hrec].
case (nreachable_dec n s); auto; intros H1.
+ right; exists n; auto.
+ left; intros m Hm; inversion Hm; auto.
+ right; case Hrec; intros m (Hm1, Hm2); exists m; split; auto with arith.
Qed.
Definition nsreachable n s :=
nreachable n s /\ forall m, m < n -> ~ nreachable m s.
Lemma nsreachable_unique n m s : nsreachable n s -> nsreachable m s -> n = m.
Proof.
intros (H1, H2) (H3, H4).
case (Nat.le_gt_cases n m); intros HH0.
apply Nat.le_lteq in HH0; destruct HH0 as [HH0|HH0]; auto.
case (H4 n); auto.
- case (H2 m); auto.
Qed.
Lemma nsreachable_bound n s :
nreachable n s -> exists m, m <= n /\ nsreachable m s.
Proof.
revert s; pattern n; apply Wf_nat.lt_wf_ind; clear n.
intros n; case n; clear n.
- intros _ s H; exists 0; split; auto with arith.
split; auto; intros m Hm; contradict Hm; auto with arith.
- intros n Hrec s Hs.
case (nreachable_le_dec (S n) s).
+ apply nreachable_valid with (1 := Hs).
+ intros H1; exists (S n); split; auto; split; auto.
+ intros (m, (Hm1, Hm2)).
case (Hrec _ Hm1 _ Hm2); intros s1 (Hs1, Hs2).
exists s1; split; auto with arith.
apply Nat.le_trans with (1 := Hs1); auto with arith.
Qed.
Lemma move_nsreachable n s2 :
nsreachable (S n) s2 -> exists s1, move s1 s2 /\ nsreachable n s1.
Proof.
intros (H1, H2).
case (move_nreachable _ _ H1); intros s1 (Hs1, Hs2).
exists s1; split; auto.
case (nsreachable_bound _ _ Hs2); intros m (Hm, Hm1).
apply Nat.le_lteq in Hm; destruct Hm as [Hm|Hm].
- case (H2 (S m)); auto with arith.
apply nreachS with (2 := Hs1); auto.
case Hm1; auto.
- subst n; auto.
Qed.
Lemma nsreachable_inv n m s :
n <= m -> nsreachable m s -> exists s1, nsreachable n s1.
Proof.
intro H; revert s; elim H; auto; clear m H.
- intros s H1; exists s; auto.
- intros m _ H1 s H2.
case (move_nsreachable _ _ H2); intros s1 (_, Hs1); auto.
apply (H1 s1); auto.
Qed.
Definition nlreachable n s := exists m, m <= n /\ nreachable m s.
Lemma nlreachable_reachable n s : nlreachable n s -> reachable s.
Proof.
intros (m, (Hm, Hm1)).
apply nreachable_reachable with m; auto.
Qed.
Lemma nlreach_weak n m s :
n <= m -> nlreachable n s -> nlreachable m s.
Proof.
intros H (m1, (Hm1, Hm2)).
exists m1; split; auto.
apply Nat.le_trans with (1 := Hm1); auto.
Qed.
Lemma nlreachable_bound n s :
nlreachable n s -> exists m, m <= n /\ nsreachable m s.
Proof.
intros (m, (H1, H2)); case (nsreachable_bound m s); auto.
intros p (Hp, Hp1); exists p; split; auto.
apply Nat.le_trans with (1 := Hp); auto.
Qed.
(*****************************************************************************)
(* *)
(* Computational version of reachability *)
(* *)
(*****************************************************************************)
(* The list of all moves *)
Definition movel :=
rright :: (fun s1 => rright (rright s1)) ::
(fun s1 => rright (rright (rright s1))) ::
rback :: (fun s1 => rback (rback s1)) ::
(fun s1 => rback (rback (rback s1))) ::
rdown:: (fun s1 => rdown (rdown s1)) ::
(fun s1 => rdown (rdown (rdown s1))):: nil.
(* The list of candidate *)
Definition candidate_list l :=
fold_right
(fun (y : state) (x : list state) =>
map (fun y1 : state -> state => y1 y) movel ++ x) nil l.
(* A filter that only adds the element that were not already in the first list *)
Definition filters (ps : states * states) (s : state) :=
let (states, nstates) := ps in
if in_states s states then ps
else (s :: states, s :: nstates).
(* Compute the next pair of states *)
Definition nexts (ps : states * states) s :=
fold_left
(fun (ps : states * states) f =>
let (states, nstates) := ps in
let s := f s in
if in_states s states then ps else
let states1 := s :: states in
let nstates1 := s :: nstates in (states1, nstates1))
movel ps.
(* Now we just iterate *)
Fixpoint iters_aux n (ps : states * states) :=
match n with
| O => ps
| S n1 => let (m,p) := ps in
iters_aux n1 (fold_left nexts p (m,nil))
end.
Definition iters n := iters_aux n (init_state :: nil, init_state :: nil).
(*****************************************************************************)
(* Proving iters *)
(*****************************************************************************)
Lemma movel_valid f s :
In f movel -> valid_state s -> valid_state (f s).
Proof.
intros [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | [H1 | H1]]]]]]]]];
try subst f;
intros; repeat apply valid_state_right;
repeat apply valid_state_back;
repeat apply valid_state_down; auto.
case H1; auto.
Qed.
Lemma candidate_list_correct l n :
(forall i, (nsreachable n i -> In i l) /\
(In i l -> nlreachable n i)) ->
(forall i, (nsreachable (S n) i -> In i (candidate_list l)) /\
(In i (candidate_list l) -> nlreachable (S n) i)).
Proof.
assert (F : forall l n i,
(forall j, move j i -> nsreachable n j -> In j l) ->
nsreachable (S n) i -> In i (candidate_list l)).
- intros l1; elim l1; simpl; auto; clear l1.
+ intros n1 i1 H Hi1.
case (move_nsreachable _ _ Hi1); intros j1 (Hj1, Hj2); auto.
apply (H j1); auto.
+ intros s l1 Hrec n1 i1 Hi Hi1.
case (move_nsreachable _ _ Hi1); intros j1 (Hj1, Hj2); auto.
case (Hi _ Hj1 Hj2); intros HH.
* rewrite <-HH in Hj1; unfold move in Hj1; clear HH; intuition.
* do 9 match goal with |- context[?X = ?Y] =>
generalize (state_eq_correct X Y);
case state_eq; auto; intros; right
end.
apply Hrec with n1; auto.
intros j Hj3 Hj4.
case (Hi _ Hj3 Hj4); auto.
intros HH1; rewrite <- HH1 in Hj3.
do 8 (case Hj3; intros HH2; contradict HH2; auto;
clear Hj3; intros Hj3).
- intros H i; split.
+ intros; apply F with n; auto.
intros; case (H j); auto.
+ assert (H1: forall i, In i l -> nlreachable n i).
intros i1; case (H i1); auto.
generalize H1; elim l; simpl; auto; clear l H H1.
* intros _ HH; case HH.
* intros a l Hrec; intros H1.
case (H1 a); auto; intros m (Hm, Hm1).
intros [HH1 | [HH1 | [HH1 | [HH1 |
[HH1 | [HH1 | [HH1 | [HH1 | [HH1 | HH1]]]]]]]]];
try (subst i; exists (S m); split; auto with arith;
apply nreachS with (1 := Hm1); unfold move; auto;
do 3 right; auto; do 3 right; auto).
apply Hrec; auto.
Qed.
Lemma candidate_valid l :
(forall s, In s l -> valid_state s) ->
(forall s, In s (candidate_list l) -> valid_state s).
Proof.
elim l; unfold candidate_list; auto; clear l.
intros a l Hrec Hg s; rewrite fold_right_cons; intros H1.
case (in_app_or _ _ _ H1); intros H2; auto with datatypes.
assert (F0: valid_state a); auto with datatypes.
rewrite in_map_iff in H2.
case H2; intros f (Hf, Hf1); subst s.
apply movel_valid; auto.
Qed.
Lemma candidate_app l1 l2 :
candidate_list (l1 ++ l2) = candidate_list l1 ++ candidate_list l2.
Proof.
revert l2; elim l1; unfold candidate_list; clear l1.
- simpl; auto.
- intros a l1 Hrec l2; rewrite fold_right_cons.
rewrite <- app_assoc, <- Hrec; auto.
Qed.
Lemma candidate_in a l :
In a (candidate_list l) <->
exists i, exists f, a = f i /\ In i l /\ In f movel.
Proof.
elim l; clear l.
- split; intros H; case H; intros i (f, (_, (HH,_))); case HH.
- intros b l Hrec; split.
+ intros H; case (in_app_or (map (fun y1 : state -> state => y1 b) movel)
(candidate_list l) _ H).
* elim movel; simpl; auto.
-- intros HH; case HH.
-- intros f lf Hrec1 [H1 | H1].
++ exists b; exists f; auto.
++ case (Hrec1 H1); intros f1 (b1, (Hb1, (Hb2, Hb3))).
exists f1; exists b1; auto.
* rewrite Hrec; intros (i, (f, (Hb1, (Hb2, Hb3)))).
exists i; exists f; auto with datatypes.
+ intros (i, (f, (Hf, (Hf1, Hf2)))); subst a.
unfold candidate_list; rewrite fold_right_cons.
match goal with |- context[fold_right ?X ?Y ?Z] =>
change (fold_right X Y Z) with (candidate_list Z)
end.
apply in_or_app.
simpl in Hf1; case Hf1; clear Hf1; intros Hf1.
* subst b; left; generalize Hf2; elim movel; simpl; auto.
intros f1 lf Hrec1 [H1 | H1]; auto; subst f1; auto.
* right; rewrite Hrec.
exists i; exists f; auto.
Qed.
Definition lequiv {A : Type} l1 l2:= forall s : A, In s l1 <-> In s l2.
Definition pequiv {A : Type} (pl1 pl2 : list A * list A) :=
lequiv (fst pl1) (fst pl2) /\ lequiv (snd pl1) (snd pl2).
Lemma candidate_equiv l1 l2 :
lequiv l1 l2 -> lequiv (candidate_list l1) (candidate_list l2).
Proof.
intros H1 a.
repeat rewrite candidate_in.
split; intros (i, (f, (Hf, (Hf1, Hf2)))); exists i; exists f; auto.