File size: 52,524 Bytes
a9ea017
 
7e1c831
 
a9ea017
7e1c831
a9ea017
7e1c831
a9ea017
 
7e1c831
a9ea017
 
7e1c831
a9ea017
 
 
 
 
7e1c831
a9ea017
 
 
 
 
 
7e1c831
a9ea017
 
 
 
 
 
 
7e1c831
 
a9ea017
 
7e1c831
a9ea017
7e1c831
a9ea017
7e1c831
 
a9ea017
 
 
 
 
7e1c831
a9ea017
 
7e1c831
 
a9ea017
 
 
 
7e1c831
a9ea017
 
7e1c831
 
a9ea017
7e1c831
a9ea017
 
7e1c831
 
a9ea017
 
 
 
 
 
 
 
 
 
 
 
7e1c831
 
a9ea017
 
 
7e1c831
 
 
 
a9ea017
 
 
 
 
 
 
 
 
 
7e1c831
a9ea017
7e1c831
a9ea017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e1c831
a9ea017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e1c831
a9ea017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e1c831
a9ea017
 
 
7e1c831
 
a9ea017
 
 
 
 
 
7e1c831
a9ea017
 
 
7e1c831
 
a9ea017
 
 
 
7e1c831
a9ea017
 
 
 
7e1c831
 
a9ea017
 
7e1c831
a9ea017
 
 
7e1c831
a9ea017
 
 
 
 
7e1c831
a9ea017
 
 
 
 
7e1c831
 
a9ea017
 
 
 
 
 
 
 
 
 
 
7e1c831
a9ea017
 
 
 
 
 
7e1c831
a9ea017
 
 
 
 
 
 
7e1c831
 
a9ea017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e1c831
a9ea017
 
 
 
7e1c831
a9ea017
7e1c831
 
 
 
 
 
 
 
a9ea017
 
7e1c831
 
 
 
 
 
 
 
 
 
 
a9ea017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e1c831
 
 
 
 
 
a9ea017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e1c831
 
 
 
 
 
 
a9ea017
 
 
7e1c831
 
 
 
 
 
 
 
a9ea017
7e1c831
 
a9ea017
 
 
 
 
 
 
 
 
 
 
 
 
7e1c831
 
 
 
a9ea017
7e1c831
a9ea017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e1c831
a9ea017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e1c831
a9ea017
 
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
(* The pass of the spec iterated over a generation. The read tape, the idle bank read as a tape of
   N cells and the copy tape keep their cells in place, each head at an absolute cell. *)
From Stdlib Require Import List Bool Arith Lia.
Import ListNotations.
From TH Require Import TwoHead Abstract Spec PassCheck.

Record dst := mkD { dc : cfg; dR : tape; dA : tape; dK : tape }.

(* a tape holding the cells u and then z, its head on the first cell of z *)
Definition past (n : nat) (u z : list bool) : tape := mkT (u ++ z) (length u mod n).

Lemma upd_app_cons : forall u c z v, upd (u ++ c :: z) (length u) v = u ++ v :: z.
Proof. induction u as [|x u IH]; intros c z v; cbn; [reflexivity | rewrite IH; reflexivity]. Qed.

Lemma past_get : forall n u b z, length u < n -> tget (past n u (b :: z)) = b.
Proof.
  intros n u b z H. unfold tget, past. cbn [td th]. rewrite (Nat.mod_small _ _ H).
  rewrite app_nth2 by lia. rewrite Nat.sub_diag. reflexivity.
Qed.

Lemma past_adv : forall n u b z, 1 <= n ->
  mkT (td (past n u (b :: z))) (succ_mod n (th (past n u (b :: z)))) = past n (u ++ [b]) z.
Proof.
  intros n u b z H. unfold past. cbn [td th]. rewrite (succ_mod_mod n (length u) H).
  rewrite <- app_assoc, length_app. cbn [app length]. rewrite Nat.add_1_r. reflexivity.
Qed.

Lemma past_write : forall n u c z v, length u < n ->
  mkT (upd (td (past n u (c :: z))) (th (past n u (c :: z))) v) (succ_mod n (th (past n u (c :: z))))
  = past n (u ++ [v]) z.
Proof.
  intros n u c z v H. unfold past. cbn [td th]. rewrite (succ_mod_mod n (length u) ltac:(lia)).
  rewrite (Nat.mod_small _ _ H), upd_app_cons, <- app_assoc, length_app. cbn [app length].
  rewrite Nat.add_1_r. reflexivity.
Qed.

Lemma past_home : forall n u z, mkT (td (past n u z)) 0 = past n [] (u ++ z).
Proof. intros n u z. unfold past. cbn [td length app]. rewrite Nat.Div0.mod_0_l. reflexivity. Qed.

Lemma skipn_repeat_false : forall a n, skipn a (repeat false n) = repeat false (n - a).
Proof.
  induction a as [|a IH]; intros [|n]; cbn [skipn repeat]; try reflexivity. exact (IH n).
Qed.

(* ---- lists ---------------------------------------------------------------------------------- *)
Lemma some_inj : forall (A : Type) (a b : A), Some a = Some b -> a = b.
Proof. intros A a b H. injection H. auto. Qed.

Lemma split_at : forall (l : list bool) n, n <= length l -> exists a c, l = a ++ c /\ length a = n.
Proof.
  intros l n H. exists (firstn n l), (skipn n l). split; [symmetry; apply firstn_skipn|].
  apply firstn_length_le. exact H.
Qed.

Lemma skipn_app_exact : forall (a b : list bool) n, length a = n -> skipn n (a ++ b) = b.
Proof. intros a b n <-. induction a as [|x a IH]; [reflexivity|]. exact IH. Qed.

Lemma firstn_app_exact : forall (a b : list bool) n, length a = n -> firstn n (a ++ b) = a.
Proof.
  intros a b n <-. induction a as [|x a IH]; [reflexivity|]. cbn [length firstn app].
  rewrite IH. reflexivity.
Qed.

Lemma translate_aux_long : forall f l X, translate_aux f l = Some X -> 4 <= length l.
Proof.
  intros [|f] l X H; [discriminate|]. cbn [translate_aux] in H.
  destruct l as [|a [|b [|c [|d l]]]]; try discriminate. cbn [length]. lia.
Qed.

Lemma translate_aux_S : forall f c3 c2 s0 s1 rest,
  translate_aux (S f) (c3 :: c2 :: s0 :: s1 :: rest) =
  if c3 && c2 then
    if s0 && s1 then match rest with [] => Some [] | _ => None end
    else if Nat.eqb (length rest) 0 then None
    else option_map (fun t => firstn 26 rest ++ t) (translate_aux f (skipn 26 rest))
  else option_map (fun t => gate_bits (if c3 then 2 else if c2 then 1 else 0) s0 s1 ++ firstn 18 rest ++ t)
                  (translate_aux f (skipn 18 rest)).
Proof. reflexivity. Qed.

Fixpoint down (n : nat) : list nat := match n with O => [0] | S m => n :: down m end.

Definition kind_of (e3 e2 : bool) : nat := if e3 then 2 else if e2 then 1 else 0.

Lemma length_gate_bits : forall k s0 s1, length (gate_bits k s0 s1) = 8.
Proof. intros [|[|[|k]]] s0 s1; reflexivity. Qed.

Lemma table_gate : forall e3 e2 s0 s1, e3 && e2 = false ->
  map (table e3 e2 s0 s1) (down 7) = gate_bits (kind_of e3 e2) s0 s1.
Proof. intros [] [] [] [] H; try discriminate; reflexivity. Qed.

(* ---- the flags of a pass ---------------------------------------------------------------------- *)
Lemma dpass_flags : forall cf r,
  (fresh (dpass cf r) = true -> home (dpass cf r) = true)
  /\ (home (dpass cf r) = true -> emit (dpass cf r) = false)
  /\ (fresh (dpass cf r) = true -> cw (dpass cf r) = false).
Proof.
  intros [p n c3 c2 c1 c0 m] r. unfold dpass. cbn [ph Spec.z Spec.c3 Spec.c2 Spec.c1 Spec.c0 mo].
  destruct p; repeat match goal with |- context [if ?b then _ else _] => destruct b end;
    cbn [fresh home emit cw]; repeat split; intro H; first [discriminate | reflexivity].
Qed.

Lemma reach_step : forall cf r, reachable cf = true -> reachable (ncf (dpass cf r)) = true.
Proof.
  intros [p n e3 e2 e1 e0 m] r H. unfold reachable in H. cbn [ph Spec.z] in H.
  unfold dpass. cbn [ph Spec.z Spec.c3 Spec.c2 Spec.c1 Spec.c0 mo].
  destruct p; apply Nat.leb_le in H; destruct (Nat.eqb n 0) eqn:E;
    repeat match goal with |- context [if ?b then _ else _] => destruct b end;
    cbn [ncf reachable ph Spec.z]; apply Nat.leb_le; lia.
Qed.

Section Dec.
Variables N L : nat.
Hypotheses (HN : 1 <= N) (HL : 1 <= L).

Definition dout (t : dst) : out := dpass (dc t) (tget (dR t)).

(* one pass of the spec on the three tapes *)
Definition dstep (t : dst) : dst :=
  let r := tget (dR t) in
  let o := dpass (dc t) r in
  mkD (ncf o) (tape_eff L (expR o r) (dR t)) (tape_eff N (expA o (tget (dA t))) (dA t))
      (tape_eff L (expK o r (tget (dK t))) (dK t)).

Fixpoint dsteps (n : nat) (t : dst) : dst := match n with O => t | S m => dsteps m (dstep t) end.

Lemma dsteps_add : forall a b t, dsteps (a + b) t = dsteps b (dsteps a t).
Proof. induction a as [|a IH]; intros b t; cbn [dsteps Nat.add]; auto. Qed.

(* no pass among the first n hands over *)
Definition quiet (n : nat) (t : dst) : Prop := forall j, j < n -> ho (dout (dsteps j t)) = false.

Lemma quiet_S : forall n t, ho (dout t) = false -> quiet n (dstep t) -> quiet (S n) t.
Proof. intros n t H0 H [|j] Hj; [exact H0|]. cbn [dsteps]. apply H. lia. Qed.

Lemma quiet_add : forall a b t, quiet a t -> quiet b (dsteps a t) -> quiet (a + b) t.
Proof.
  intros a b t Ha Hb j Hj. destruct (Nat.lt_ge_cases j a) as [H|H]; [apply Ha; exact H|].
  replace j with (a + (j - a)) by lia. rewrite dsteps_add. apply Hb. lia.
Qed.

Lemma quiet_0 : forall t, quiet 0 t.
Proof. intros t j Hj. lia. Qed.

(* the effect of a pass on each tape, by its flags *)
Definition rmove (o : out) (t : tape) : tape :=
  if rr o then mkT (td t) 0 else if cons o then mkT (td t) (succ_mod L (th t)) else t.
Definition amove (o : out) (t : tape) : tape :=
  if fresh o then mkT (repeat false N) 0 else if home o then mkT (td t) 0
  else if emit o then mkT (upd (td t) (th t) (av o)) (succ_mod N (th t)) else t.
Definition kmove (o : out) (r : bool) (t : tape) : tape :=
  if fresh o then mkT (repeat false L) 0
  else if home o then mkT (if cw o then upd (td t) (th t) r else td t) 0
  else if cw o then mkT (upd (td t) (th t) r) (succ_mod L (th t)) else t.

Lemma dstep_eq : forall t, dstep t =
  mkD (ncf (dout t)) (rmove (dout t) (dR t)) (amove (dout t) (dA t)) (kmove (dout t) (tget (dR t)) (dK t)).
Proof.
  intros [c R A K]. unfold dstep, dout. cbn [dc dR dA dK].
  destruct (dpass_flags c (tget R)) as (F1 & F2 & F3).
  set (o := dpass c (tget R)) in *. f_equal.
  - unfold tape_eff, expR, rmove. cbn [acl awr amv arw].
    destruct (rr o), (cons o); cbn [iter]; try reflexivity. destruct R; reflexivity.
  - unfold tape_eff, expA, amove, tget. cbn [acl awr amv arw].
    destruct (fresh o) eqn:Ef; [rewrite (F1 eq_refl); reflexivity|].
    destruct (home o) eqn:Eh; [rewrite (F2 eq_refl), upd_same; reflexivity|].
    destruct (emit o); cbn [iter]; [reflexivity|]. rewrite upd_same. destruct A; reflexivity.
  - unfold tape_eff, expK, kmove, tget. cbn [acl awr amv arw].
    destruct (fresh o) eqn:Ef; [rewrite (F1 eq_refl); reflexivity|].
    destruct (home o), (cw o); cbn [iter]; rewrite ?upd_same; try reflexivity. destruct K; reflexivity.
Qed.

(* ---- one pass in each phase ---------------------------------------------------------------- *)
Lemma pass_PI : forall zc c3 c2 c1 c0 m R A K,
  ho (dout (mkD (mkC PI zc c3 c2 c1 c0 m) R A K)) = false
  /\ dstep (mkD (mkC PI zc c3 c2 c1 c0 m) R A K)
     = mkD (mkC PC 3 c3 c2 c1 c0 false) (mkT (td R) 0) (mkT (repeat false N) 0) (mkT (repeat false L) 0).
Proof. intros. split; [reflexivity|]. rewrite dstep_eq. reflexivity. Qed.

Lemma pass_PA : forall n e3 e2 e1 e0 m done b rest A K, length done < L ->
  ho (dout (mkD (mkC PA n e3 e2 e1 e0 m) (past L done (b :: rest)) A K)) = false
  /\ dstep (mkD (mkC PA n e3 e2 e1 e0 m) (past L done (b :: rest)) A K)
     = mkD (if Nat.eqb n 0 then mkC PC 3 e3 e2 e1 e0 m else mkC PA (n - 1) e3 e2 e1 e0 m)
           (past L (done ++ [b]) rest)
           (if m then A else mkT (upd (td A) (th A) b) (succ_mod N (th A)))
           (if m then mkT (upd (td K) (th K) b) (succ_mod L (th K)) else K).
Proof.
  intros n e3 e2 e1 e0 m done b rest A K Hd.
  assert (Ho : dout (mkD (mkC PA n e3 e2 e1 e0 m) (past L done (b :: rest)) A K)
               = mkO (if Nat.eqb n 0 then mkC PC 3 e3 e2 e1 e0 m else mkC PA (n - 1) e3 e2 e1 e0 m)
                     true (negb m) b m false false false false).
  { unfold dout. cbn [dc dR]. rewrite (past_get L done b rest Hd). reflexivity. }
  split; [rewrite Ho; reflexivity|].
  rewrite dstep_eq, Ho. cbn [dR dA dK]. rewrite (past_get L done b rest Hd).
  unfold rmove, amove, kmove. cbn [ncf rr cons fresh home emit cw av].
  rewrite (past_adv L done b rest HL). destruct m; reflexivity.
Qed.

Lemma pass_PG : forall n e3 e2 e1 e0 m R A K,
  ho (dout (mkD (mkC PG n e3 e2 e1 e0 m) R A K)) = false
  /\ dstep (mkD (mkC PG n e3 e2 e1 e0 m) R A K)
     = mkD (if Nat.eqb n 0 then mkC PA 17 e3 e2 e1 e0 m else mkC PG (n - 1) e3 e2 e1 e0 m)
           (if is_esc e3 e2 e1 e0 then mkT (td R) (succ_mod L (th R)) else R)
           (if m then A
            else mkT (upd (td A) (th A) (if is_esc e3 e2 e1 e0 then tget R else table e3 e2 e1 e0 n))
                     (succ_mod N (th A)))
           (if m && is_esc e3 e2 e1 e0 then mkT (upd (td K) (th K) (tget R)) (succ_mod L (th K)) else K).
Proof.
  intros n e3 e2 e1 e0 m R A K.
  assert (Ho : dout (mkD (mkC PG n e3 e2 e1 e0 m) R A K)
               = mkO (if Nat.eqb n 0 then mkC PA 17 e3 e2 e1 e0 m else mkC PG (n - 1) e3 e2 e1 e0 m)
                     (is_esc e3 e2 e1 e0) (negb m)
                     (if is_esc e3 e2 e1 e0 then tget R else table e3 e2 e1 e0 n)
                     (m && is_esc e3 e2 e1 e0) false false false false) by reflexivity.
  split; [rewrite Ho; reflexivity|].
  rewrite dstep_eq, Ho. cbn [dR dA dK]. unfold rmove, amove, kmove. cbn [ncf rr cons fresh home emit cw av].
  destruct (is_esc e3 e2 e1 e0), m; reflexivity.
Qed.

Lemma pass_PC : forall n e3 e2 e1 e0 m done b rest A K, length done < L ->
  ho (dout (mkD (mkC PC (S n) e3 e2 e1 e0 m) (past L done (b :: rest)) A K)) = false
  /\ dstep (mkD (mkC PC (S n) e3 e2 e1 e0 m) (past L done (b :: rest)) A K)
     = mkD (mkC PC n e2 e1 e0 b m) (past L (done ++ [b]) rest) A
           (if m then mkT (upd (td K) (th K) b) (succ_mod L (th K)) else K).
Proof.
  intros n e3 e2 e1 e0 m done b rest A K Hd.
  assert (Ho : dout (mkD (mkC PC (S n) e3 e2 e1 e0 m) (past L done (b :: rest)) A K)
               = mkO (mkC PC n e2 e1 e0 b m) true false false m false false false false).
  { unfold dout. cbn [dc dR]. rewrite (past_get L done b rest Hd). unfold dpass.
    cbn [ph Spec.z Spec.c3 Spec.c2 Spec.c1 Spec.c0 mo Nat.eqb]. replace (S n - 1) with n by lia. reflexivity. }
  split; [rewrite Ho; reflexivity|].
  rewrite dstep_eq, Ho. cbn [dR dA dK]. rewrite (past_get L done b rest Hd).
  unfold rmove, amove, kmove. cbn [ncf rr cons fresh home emit cw av].
  rewrite (past_adv L done b rest HL). destruct m; reflexivity.
Qed.

(* the pass that ends a codon: the codon register then holds c2 c1 c0 b *)
Lemma pass_PC0 : forall c3 c2 c1 c0 m done b rest A K, length done < L ->
  let o := dout (mkD (mkC PC 0 c3 c2 c1 c0 m) (past L done (b :: rest)) A K) in
  o = (if is_end c2 c1 c0 b then
         if m then mkO (mkC PI 1 c2 c1 c0 b false) true false false true false true false true
         else mkO (mkC PC 3 c2 c1 c0 b true) true false false false true false false false
       else if negb m || is_esc c2 c1 c0 b then mkO (mkC PG 7 c2 c1 c0 b m) true false false m false false false false
       else mkO (mkC PA 17 c2 c1 c0 b m) true false false m false false false false)
  /\ dstep (mkD (mkC PC 0 c3 c2 c1 c0 m) (past L done (b :: rest)) A K)
     = mkD (ncf o) (rmove o (past L done (b :: rest))) (amove o A) (kmove o b K).
Proof.
  intros c3 c2 c1 c0 m done b rest A K Hd o.
  split.
  - unfold o, dout. cbn [dc dR]. rewrite (past_get L done b rest Hd). reflexivity.
  - rewrite dstep_eq. cbn [dR dA dK]. fold o. rewrite (past_get L done b rest Hd). reflexivity.
Qed.

(* ---- the phases ------------------------------------------------------------------------------ *)
Lemma pa_construct : forall n e3 e2 e1 e0 done bs rest U W Z K,
  length bs = S n -> length W = S n -> length done + S n <= L -> length U + S n <= N ->
  quiet (S n) (mkD (mkC PA n e3 e2 e1 e0 false) (past L done (bs ++ rest)) (past N U (W ++ Z)) K)
  /\ dsteps (S n) (mkD (mkC PA n e3 e2 e1 e0 false) (past L done (bs ++ rest)) (past N U (W ++ Z)) K)
     = mkD (mkC PC 3 e3 e2 e1 e0 false) (past L (done ++ bs) rest) (past N (U ++ bs) Z) K.
Proof.
  induction n as [|n IH]; intros e3 e2 e1 e0 done bs rest U W Z K Hb HW Hd HU;
    (destruct bs as [|b bs]; [discriminate|]); (destruct W as [|w W]; [discriminate|]);
    cbn [app length] in *;
    match goal with |- context [mkC PA ?k _ _ _ _ _] =>
      destruct (pass_PA k e3 e2 e1 e0 false done b (bs ++ rest) (past N U (w :: W ++ Z)) K ltac:(lia)) as [Hq Hs] end;
    rewrite (past_write N U w (W ++ Z) b ltac:(lia)) in Hs.
  - destruct bs; [|discriminate]. destruct W; [|discriminate]. cbn [app Nat.eqb] in Hs, Hq |- *.
    split; [apply quiet_S; [exact Hq | apply quiet_0]|]. cbn [dsteps]. rewrite Hs. reflexivity.
  - cbn [Nat.eqb] in Hs. replace (S n - 1) with n in Hs by lia.
    destruct (IH e3 e2 e1 e0 (done ++ [b]) bs rest (U ++ [b]) W Z K ltac:(lia) ltac:(lia)
                ltac:(rewrite length_app; cbn [length]; lia) ltac:(rewrite length_app; cbn [length]; lia))
      as [Q E].
    rewrite <- Hs in Q, E. split; [apply quiet_S; [exact Hq | exact Q]|].
    change (dsteps (S (S n)) ?t) with (dsteps (S n) (dstep t)). rewrite E, <- !app_assoc. reflexivity.
Qed.

Lemma pa_copy : forall n e3 e2 e1 e0 done bs rest A V W C,
  length bs = S n -> length W = S n -> length done + S n <= L -> length V + S n <= L ->
  quiet (S n) (mkD (mkC PA n e3 e2 e1 e0 true) (past L done (bs ++ rest)) A (past L V (W ++ C)))
  /\ dsteps (S n) (mkD (mkC PA n e3 e2 e1 e0 true) (past L done (bs ++ rest)) A (past L V (W ++ C)))
     = mkD (mkC PC 3 e3 e2 e1 e0 true) (past L (done ++ bs) rest) A (past L (V ++ bs) C).
Proof.
  induction n as [|n IH]; intros e3 e2 e1 e0 done bs rest A V W C Hb HW Hd HV;
    (destruct bs as [|b bs]; [discriminate|]); (destruct W as [|w W]; [discriminate|]);
    cbn [app length] in *;
    match goal with |- context [mkC PA ?k _ _ _ _ _] =>
      destruct (pass_PA k e3 e2 e1 e0 true done b (bs ++ rest) A (past L V (w :: W ++ C)) ltac:(lia)) as [Hq Hs] end;
    rewrite (past_write L V w (W ++ C) b ltac:(lia)) in Hs.
  - destruct bs; [|discriminate]. destruct W; [|discriminate]. cbn [app Nat.eqb] in Hs, Hq |- *.
    split; [apply quiet_S; [exact Hq | apply quiet_0]|]. cbn [dsteps]. rewrite Hs. reflexivity.
  - cbn [Nat.eqb] in Hs. replace (S n - 1) with n in Hs by lia.
    destruct (IH e3 e2 e1 e0 (done ++ [b]) bs rest A (V ++ [b]) W C ltac:(lia) ltac:(lia)
                ltac:(rewrite length_app; cbn [length]; lia) ltac:(rewrite length_app; cbn [length]; lia))
      as [Q E].
    rewrite <- Hs in Q, E. split; [apply quiet_S; [exact Hq | exact Q]|].
    change (dsteps (S (S n)) ?t) with (dsteps (S n) (dstep t)). rewrite E, <- !app_assoc. reflexivity.
Qed.

Lemma pg_gate : forall n e3 e2 e1 e0 R U W Z K, is_esc e3 e2 e1 e0 = false ->
  length W = S n -> length U + S n <= N ->
  quiet (S n) (mkD (mkC PG n e3 e2 e1 e0 false) R (past N U (W ++ Z)) K)
  /\ dsteps (S n) (mkD (mkC PG n e3 e2 e1 e0 false) R (past N U (W ++ Z)) K)
     = mkD (mkC PA 17 e3 e2 e1 e0 false) R (past N (U ++ map (table e3 e2 e1 e0) (down n)) Z) K.
Proof.
  induction n as [|n IH]; intros e3 e2 e1 e0 R U W Z K He HW HU;
    (destruct W as [|w W]; [discriminate|]); cbn [app length] in *;
    match goal with |- context [mkC PG ?k _ _ _ _ _] =>
      destruct (pass_PG k e3 e2 e1 e0 false R (past N U (w :: W ++ Z)) K) as [Hq Hs] end;
    rewrite He in Hs; cbn [andb negb] in Hs;
    rewrite (past_write N U w (W ++ Z) _ ltac:(lia)) in Hs.
  - destruct W; [|discriminate]. cbn [app Nat.eqb] in Hs, Hq |- *.
    split; [apply quiet_S; [exact Hq | apply quiet_0]|]. cbn [dsteps]. rewrite Hs. reflexivity.
  - cbn [Nat.eqb] in Hs. replace (S n - 1) with n in Hs by lia.
    destruct (IH e3 e2 e1 e0 R (U ++ [table e3 e2 e1 e0 (S n)]) W Z K He ltac:(lia)
                ltac:(rewrite length_app; cbn [length]; lia)) as [Q E].
    rewrite <- Hs in Q, E. split; [apply quiet_S; [exact Hq | exact Q]|].
    change (dsteps (S (S n)) ?t) with (dsteps (S n) (dstep t)). rewrite E, <- !app_assoc. reflexivity.
Qed.

Lemma pg_esc_construct : forall n e3 e2 e1 e0 done bs rest U W Z K, is_esc e3 e2 e1 e0 = true ->
  length bs = S n -> length W = S n -> length done + S n <= L -> length U + S n <= N ->
  quiet (S n) (mkD (mkC PG n e3 e2 e1 e0 false) (past L done (bs ++ rest)) (past N U (W ++ Z)) K)
  /\ dsteps (S n) (mkD (mkC PG n e3 e2 e1 e0 false) (past L done (bs ++ rest)) (past N U (W ++ Z)) K)
     = mkD (mkC PA 17 e3 e2 e1 e0 false) (past L (done ++ bs) rest) (past N (U ++ bs) Z) K.
Proof.
  induction n as [|n IH]; intros e3 e2 e1 e0 done bs rest U W Z K He Hb HW Hd HU;
    (destruct bs as [|b bs]; [discriminate|]); (destruct W as [|w W]; [discriminate|]);
    cbn [app length] in *;
    match goal with |- context [mkC PG ?k _ _ _ _ _] =>
      destruct (pass_PG k e3 e2 e1 e0 false (past L done (b :: bs ++ rest)) (past N U (w :: W ++ Z)) K)
        as [Hq Hs] end;
    rewrite He in Hs; cbn [andb negb] in Hs;
    rewrite (past_get L done b (bs ++ rest) ltac:(lia)), (past_adv L done b (bs ++ rest) HL),
      (past_write N U w (W ++ Z) b ltac:(lia)) in Hs.
  - destruct bs; [|discriminate]. destruct W; [|discriminate]. cbn [app Nat.eqb] in Hs, Hq |- *.
    split; [apply quiet_S; [exact Hq | apply quiet_0]|]. cbn [dsteps]. rewrite Hs. reflexivity.
  - cbn [Nat.eqb] in Hs. replace (S n - 1) with n in Hs by lia.
    destruct (IH e3 e2 e1 e0 (done ++ [b]) bs rest (U ++ [b]) W Z K He ltac:(lia) ltac:(lia)
                ltac:(rewrite length_app; cbn [length]; lia) ltac:(rewrite length_app; cbn [length]; lia))
      as [Q E].
    rewrite <- Hs in Q, E. split; [apply quiet_S; [exact Hq | exact Q]|].
    change (dsteps (S (S n)) ?t) with (dsteps (S n) (dstep t)). rewrite E, <- !app_assoc. reflexivity.
Qed.

Lemma pg_esc_copy : forall n e3 e2 e1 e0 done bs rest A V W C, is_esc e3 e2 e1 e0 = true ->
  length bs = S n -> length W = S n -> length done + S n <= L -> length V + S n <= L ->
  quiet (S n) (mkD (mkC PG n e3 e2 e1 e0 true) (past L done (bs ++ rest)) A (past L V (W ++ C)))
  /\ dsteps (S n) (mkD (mkC PG n e3 e2 e1 e0 true) (past L done (bs ++ rest)) A (past L V (W ++ C)))
     = mkD (mkC PA 17 e3 e2 e1 e0 true) (past L (done ++ bs) rest) A (past L (V ++ bs) C).
Proof.
  induction n as [|n IH]; intros e3 e2 e1 e0 done bs rest A V W C He Hb HW Hd HV;
    (destruct bs as [|b bs]; [discriminate|]); (destruct W as [|w W]; [discriminate|]);
    cbn [app length] in *;
    match goal with |- context [mkC PG ?k _ _ _ _ _] =>
      destruct (pass_PG k e3 e2 e1 e0 true (past L done (b :: bs ++ rest)) A (past L V (w :: W ++ C)))
        as [Hq Hs] end;
    rewrite He in Hs; cbn [andb negb] in Hs;
    rewrite (past_get L done b (bs ++ rest) ltac:(lia)), (past_adv L done b (bs ++ rest) HL),
      (past_write L V w (W ++ C) b ltac:(lia)) in Hs.
  - destruct bs; [|discriminate]. destruct W; [|discriminate]. cbn [app Nat.eqb] in Hs, Hq |- *.
    split; [apply quiet_S; [exact Hq | apply quiet_0]|]. cbn [dsteps]. rewrite Hs. reflexivity.
  - cbn [Nat.eqb] in Hs. replace (S n - 1) with n in Hs by lia.
    destruct (IH e3 e2 e1 e0 (done ++ [b]) bs rest A (V ++ [b]) W C He ltac:(lia) ltac:(lia)
                ltac:(rewrite length_app; cbn [length]; lia) ltac:(rewrite length_app; cbn [length]; lia))
      as [Q E].
    rewrite <- Hs in Q, E. split; [apply quiet_S; [exact Hq | exact Q]|].
    change (dsteps (S (S n)) ?t) with (dsteps (S n) (dstep t)). rewrite E, <- !app_assoc. reflexivity.
Qed.

(* the first three passes of a codon *)
Lemma codon3_construct : forall b3 b2 b1 b0 e3 e2 e1 e0 done rest A K, length done + 3 < L ->
  quiet 3 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done ([e3; e2; e1; e0] ++ rest)) A K)
  /\ dsteps 3 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done ([e3; e2; e1; e0] ++ rest)) A K)
     = mkD (mkC PC 0 b0 e3 e2 e1 false) (past L (done ++ [e3; e2; e1]) (e0 :: rest)) A K.
Proof.
  intros b3 b2 b1 b0 e3 e2 e1 e0 done rest A K Hd. cbn [app].
  destruct (pass_PC 2 b3 b2 b1 b0 false done e3 (e2 :: e1 :: e0 :: rest) A K ltac:(lia)) as [Q1 E1].
  destruct (pass_PC 1 b2 b1 b0 e3 false (done ++ [e3]) e2 (e1 :: e0 :: rest) A K
              ltac:(rewrite length_app; cbn [length]; lia)) as [Q2 E2].
  destruct (pass_PC 0 b1 b0 e3 e2 false ((done ++ [e3]) ++ [e2]) e1 (e0 :: rest) A K
              ltac:(rewrite !length_app; cbn [length]; lia)) as [Q3 E3].
  split.
  - apply quiet_S; [exact Q1|]. rewrite E1. apply quiet_S; [exact Q2|]. rewrite E2.
    apply quiet_S; [exact Q3|]. apply quiet_0.
  - cbn [dsteps]. rewrite E1, E2, E3, <- !app_assoc. reflexivity.
Qed.

Lemma codon3_copy : forall b3 b2 b1 b0 e3 e2 e1 e0 done rest A V w1 w2 w3 C,
  length done + 3 < L -> length V + 3 < L ->
  quiet 3 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done ([e3; e2; e1; e0] ++ rest)) A
               (past L V (w1 :: w2 :: w3 :: C)))
  /\ dsteps 3 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done ([e3; e2; e1; e0] ++ rest)) A
                   (past L V (w1 :: w2 :: w3 :: C)))
     = mkD (mkC PC 0 b0 e3 e2 e1 true) (past L (done ++ [e3; e2; e1]) (e0 :: rest)) A
           (past L (V ++ [e3; e2; e1]) C).
Proof.
  intros b3 b2 b1 b0 e3 e2 e1 e0 done rest A V w1 w2 w3 C Hd HV. cbn [app].
  destruct (pass_PC 2 b3 b2 b1 b0 true done e3 (e2 :: e1 :: e0 :: rest) A (past L V (w1 :: w2 :: w3 :: C))
              ltac:(lia)) as [Q1 E1].
  rewrite (past_write L V w1 (w2 :: w3 :: C) e3 ltac:(lia)) in E1.
  destruct (pass_PC 1 b2 b1 b0 e3 true (done ++ [e3]) e2 (e1 :: e0 :: rest) A (past L (V ++ [e3]) (w2 :: w3 :: C))
              ltac:(rewrite length_app; cbn [length]; lia)) as [Q2 E2].
  rewrite (past_write L (V ++ [e3]) w2 (w3 :: C) e2 ltac:(rewrite length_app; cbn [length]; lia)) in E2.
  destruct (pass_PC 0 b1 b0 e3 e2 true ((done ++ [e3]) ++ [e2]) e1 (e0 :: rest) A
              (past L ((V ++ [e3]) ++ [e2]) (w3 :: C)) ltac:(rewrite !length_app; cbn [length]; lia)) as [Q3 E3].
  rewrite (past_write L ((V ++ [e3]) ++ [e2]) w3 C e1 ltac:(rewrite !length_app; cbn [length]; lia)) in E3.
  split.
  - apply quiet_S; [exact Q1|]. rewrite E1. apply quiet_S; [exact Q2|]. rewrite E2.
    apply quiet_S; [exact Q3|]. apply quiet_0.
  - cbn [dsteps]. rewrite E1, E2, E3, <- !app_assoc. reflexivity.
Qed.

(* ---- composing passes ------------------------------------------------------------------------ *)
Lemma one : forall t t', ho (dout t) = false -> dstep t = t' -> quiet 1 t /\ dsteps 1 t = t'.
Proof. intros t t' H E. split; [apply quiet_S; [exact H | apply quiet_0] | cbn [dsteps]; exact E]. Qed.

Lemma chain : forall a b t t' t'', quiet a t /\ dsteps a t = t' -> quiet b t' /\ dsteps b t' = t'' ->
  quiet (a + b) t /\ dsteps (a + b) t = t''.
Proof.
  intros a b t t' t'' [Qa Ea] [Qb Eb]. split.
  - apply quiet_add; [exact Qa|]. rewrite Ea. exact Qb.
  - rewrite dsteps_add, Ea. exact Eb.
Qed.

(* a run of passes whose last pass, and only that one, hands over *)
Lemma chain_last : forall a b t t' t'', quiet a t /\ dsteps a t = t' ->
  quiet (b - 1) t' /\ ho (dout (dsteps (b - 1) t')) = true /\ dsteps b t' = t'' -> 1 <= b ->
  quiet (a + b - 1) t /\ ho (dout (dsteps (a + b - 1) t)) = true /\ dsteps (a + b) t = t''.
Proof.
  intros a b t t' t'' [Qa Ea] (Qb & Hb & Eb) H1.
  replace (a + b - 1) with (a + (b - 1)) by lia.
  split; [apply quiet_add; [exact Qa | rewrite Ea; exact Qb]|].
  split; rewrite dsteps_add, Ea; assumption.
Qed.

Lemma skipn_app_plus : forall (a b : list bool) k, skipn (length a + k) (a ++ b) = skipn k b.
Proof. induction a as [|x a IH]; intros b k; [reflexivity|]. exact (IH b k). Qed.

(* lists of cells to the right-nested form with the known cells first *)
Ltac norm_in H := repeat (first [rewrite <- app_assoc in H | progress (cbn [app] in H)]).
Ltac norm_goal := repeat (first [rewrite <- app_assoc | progress (cbn [app])]).

(* ---- the pass that ends a codon ------------------------------------------------------------- *)
Lemma pc0_construct_go : forall c3 c2 c1 c0 done b rest A K, length done < L -> is_end c2 c1 c0 b = false ->
  quiet 1 (mkD (mkC PC 0 c3 c2 c1 c0 false) (past L done (b :: rest)) A K)
  /\ dsteps 1 (mkD (mkC PC 0 c3 c2 c1 c0 false) (past L done (b :: rest)) A K)
     = mkD (mkC PG 7 c2 c1 c0 b false) (past L (done ++ [b]) rest) A K.
Proof.
  intros c3 c2 c1 c0 done b rest A K Hd Hn.
  destruct (pass_PC0 c3 c2 c1 c0 false done b rest A K Hd) as [O E].
  rewrite Hn in O. cbn [negb orb] in O.
  apply one; [rewrite O; reflexivity|]. rewrite E, O. unfold rmove, amove, kmove.
  cbn [ncf rr cons fresh home emit cw]. rewrite (past_adv L done b rest HL). reflexivity.
Qed.

Lemma pc0_construct_end : forall c3 c2 c1 c0 done b rest A K, length done < L -> is_end c2 c1 c0 b = true ->
  quiet 1 (mkD (mkC PC 0 c3 c2 c1 c0 false) (past L done (b :: rest)) A K)
  /\ dsteps 1 (mkD (mkC PC 0 c3 c2 c1 c0 false) (past L done (b :: rest)) A K)
     = mkD (mkC PC 3 c2 c1 c0 b true) (past L [] (done ++ b :: rest)) A K.
Proof.
  intros c3 c2 c1 c0 done b rest A K Hd Hn.
  destruct (pass_PC0 c3 c2 c1 c0 false done b rest A K Hd) as [O E].
  rewrite Hn in O.
  apply one; [rewrite O; reflexivity|]. rewrite E, O. unfold rmove, amove, kmove.
  cbn [ncf rr cons fresh home emit cw]. rewrite past_home. reflexivity.
Qed.

Lemma pc0_copy_go : forall c3 c2 c1 c0 done b rest A V w C, length done < L -> length V < L ->
  is_end c2 c1 c0 b = false ->
  quiet 1 (mkD (mkC PC 0 c3 c2 c1 c0 true) (past L done (b :: rest)) A (past L V (w :: C)))
  /\ dsteps 1 (mkD (mkC PC 0 c3 c2 c1 c0 true) (past L done (b :: rest)) A (past L V (w :: C)))
     = mkD (if is_esc c2 c1 c0 b then mkC PG 7 c2 c1 c0 b true else mkC PA 17 c2 c1 c0 b true)
           (past L (done ++ [b]) rest) A (past L (V ++ [b]) C).
Proof.
  intros c3 c2 c1 c0 done b rest A V w C Hd HV Hn.
  destruct (pass_PC0 c3 c2 c1 c0 true done b rest A (past L V (w :: C)) Hd) as [O E].
  rewrite Hn in O. cbn [negb orb] in O.
  apply one; [rewrite O; destruct (is_esc c2 c1 c0 b); reflexivity|].
  rewrite E, O. destruct (is_esc c2 c1 c0 b); unfold rmove, amove, kmove;
    cbn [ncf rr cons fresh home emit cw];
    rewrite (past_adv L done b rest HL), (past_write L V w C b HV); reflexivity.
Qed.

Lemma pc0_copy_end : forall c3 c2 c1 c0 done b rest A V w C, length done < L -> length V < L ->
  is_end c2 c1 c0 b = true ->
  ho (dout (mkD (mkC PC 0 c3 c2 c1 c0 true) (past L done (b :: rest)) A (past L V (w :: C)))) = true
  /\ dstep (mkD (mkC PC 0 c3 c2 c1 c0 true) (past L done (b :: rest)) A (past L V (w :: C)))
     = mkD (mkC PI 1 c2 c1 c0 b false) (past L (done ++ [b]) rest) (mkT (td A) 0) (mkT (V ++ b :: C) 0).
Proof.
  intros c3 c2 c1 c0 done b rest A V w C Hd HV Hn.
  destruct (pass_PC0 c3 c2 c1 c0 true done b rest A (past L V (w :: C)) Hd) as [O E].
  rewrite Hn in O.
  split; [rewrite O; reflexivity|].
  assert (Hk : upd (td (past L V (w :: C))) (th (past L V (w :: C))) b = V ++ b :: C)
    by (unfold past; cbn [td th]; rewrite (Nat.mod_small _ _ HV); apply upd_app_cons).
  rewrite E, O. unfold rmove, amove, kmove. cbn [ncf rr cons fresh home emit cw].
  rewrite (past_adv L done b rest HL), Hk. reflexivity.
Qed.

(* ---- a whole codon ------------------------------------------------------------------------------ *)
Lemma codon_construct_go : forall b3 b2 b1 b0 e3 e2 e1 e0 done rest A K, length done + 4 <= L ->
  is_end e3 e2 e1 e0 = false ->
  quiet 4 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (e3 :: e2 :: e1 :: e0 :: rest)) A K)
  /\ dsteps 4 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (e3 :: e2 :: e1 :: e0 :: rest)) A K)
     = mkD (mkC PG 7 e3 e2 e1 e0 false) (past L (done ++ [e3; e2; e1; e0]) rest) A K.
Proof.
  intros b3 b2 b1 b0 e3 e2 e1 e0 done rest A K Hd Hn.
  destruct (pc0_construct_go b0 e3 e2 e1 (done ++ [e3; e2; e1]) e0 rest A K
              ltac:(rewrite length_app; cbn [length]; lia) Hn) as [Q E].
  rewrite <- app_assoc in E. cbn [app] in E.
  exact (chain 3 1 _ _ _ (codon3_construct b3 b2 b1 b0 e3 e2 e1 e0 done rest A K ltac:(lia)) (conj Q E)).
Qed.

Lemma codon_construct_end : forall b3 b2 b1 b0 done rest A K, length done + 4 <= L ->
  quiet 4 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (true :: true :: true :: true :: rest)) A K)
  /\ dsteps 4 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (true :: true :: true :: true :: rest)) A K)
     = mkD (mkC PC 3 true true true true true) (past L [] (done ++ true :: true :: true :: true :: rest)) A K.
Proof.
  intros b3 b2 b1 b0 done rest A K Hd.
  destruct (pc0_construct_end b0 true true true (done ++ [true; true; true]) true rest A K
              ltac:(rewrite length_app; cbn [length]; lia) eq_refl) as [Q E].
  rewrite <- app_assoc in E. cbn [app] in E.
  exact (chain 3 1 _ _ _ (codon3_construct b3 b2 b1 b0 true true true true done rest A K ltac:(lia)) (conj Q E)).
Qed.

Lemma codon_copy_go : forall b3 b2 b1 b0 e3 e2 e1 e0 done rest A V w1 w2 w3 w4 C,
  length done + 4 <= L -> length V + 4 <= L -> is_end e3 e2 e1 e0 = false ->
  quiet 4 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (e3 :: e2 :: e1 :: e0 :: rest)) A
               (past L V (w1 :: w2 :: w3 :: w4 :: C)))
  /\ dsteps 4 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (e3 :: e2 :: e1 :: e0 :: rest)) A
                   (past L V (w1 :: w2 :: w3 :: w4 :: C)))
     = mkD (if is_esc e3 e2 e1 e0 then mkC PG 7 e3 e2 e1 e0 true else mkC PA 17 e3 e2 e1 e0 true)
           (past L (done ++ [e3; e2; e1; e0]) rest) A (past L (V ++ [e3; e2; e1; e0]) C).
Proof.
  intros b3 b2 b1 b0 e3 e2 e1 e0 done rest A V w1 w2 w3 w4 C Hd HV Hn.
  destruct (pc0_copy_go b0 e3 e2 e1 (done ++ [e3; e2; e1]) e0 rest A (V ++ [e3; e2; e1]) w4 C
              ltac:(rewrite length_app; cbn [length]; lia) ltac:(rewrite length_app; cbn [length]; lia) Hn)
    as [Q E].
  rewrite <- !app_assoc in E. cbn [app] in E.
  exact (chain 3 1 _ _ _ (codon3_copy b3 b2 b1 b0 e3 e2 e1 e0 done rest A V w1 w2 w3 (w4 :: C)
                            ltac:(lia) ltac:(lia)) (conj Q E)).
Qed.

Lemma codon_copy_end : forall b3 b2 b1 b0 done rest A V w1 w2 w3 w4 C,
  length done + 4 <= L -> length V + 4 <= L ->
  quiet 3 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (true :: true :: true :: true :: rest)) A
               (past L V (w1 :: w2 :: w3 :: w4 :: C)))
  /\ ho (dout (dsteps 3 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (true :: true :: true :: true :: rest)) A
                             (past L V (w1 :: w2 :: w3 :: w4 :: C))))) = true
  /\ dsteps 4 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (true :: true :: true :: true :: rest)) A
                   (past L V (w1 :: w2 :: w3 :: w4 :: C)))
     = mkD (mkC PI 1 true true true true false) (past L (done ++ [true; true; true; true]) rest)
           (mkT (td A) 0) (mkT (V ++ true :: true :: true :: true :: C) 0).
Proof.
  intros b3 b2 b1 b0 done rest A V w1 w2 w3 w4 C Hd HV.
  destruct (codon3_copy b3 b2 b1 b0 true true true true done rest A V w1 w2 w3 (w4 :: C) ltac:(lia) ltac:(lia))
    as [Q E].
  cbn [app] in Q, E.
  destruct (pc0_copy_end b0 true true true (done ++ [true; true; true]) true rest A (V ++ [true; true; true]) w4 C
              ltac:(rewrite length_app; cbn [length]; lia) ltac:(rewrite length_app; cbn [length]; lia) eq_refl)
    as [H4 E4].
  rewrite <- !app_assoc in E4. cbn [app] in E4.
  split; [exact Q|]. split; [rewrite E; exact H4|].
  change 4 with (3 + 1). rewrite dsteps_add, E. cbn [dsteps]. exact E4.
Qed.

(* ---- one record of the description, and its end -------------------------------------------- *)
Lemma seg_gate : forall b3 b2 b1 b0 e3 e2 s0 s1 addr rest done U W Z K,
  e3 && e2 = false -> length addr = 18 -> length W = 26 -> length done + 22 <= L -> length U + 26 <= N ->
  quiet 30 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (e3 :: e2 :: s0 :: s1 :: addr ++ rest))
                (past N U (W ++ Z)) K)
  /\ dsteps 30 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (e3 :: e2 :: s0 :: s1 :: addr ++ rest))
                    (past N U (W ++ Z)) K)
     = mkD (mkC PC 3 e3 e2 s0 s1 false) (past L (done ++ e3 :: e2 :: s0 :: s1 :: addr) rest)
           (past N (U ++ gate_bits (kind_of e3 e2) s0 s1 ++ addr) Z) K.
Proof.
  intros b3 b2 b1 b0 e3 e2 s0 s1 addr rest done U W Z K H32 Ha HW Hd HU.
  assert (He : is_esc e3 e2 s0 s1 = false) by (unfold is_esc; rewrite H32; reflexivity).
  assert (Hn : is_end e3 e2 s0 s1 = false) by (unfold is_end; rewrite H32; reflexivity).
  destruct (split_at W 8 ltac:(lia)) as (W1 & W2 & -> & HW1). rewrite length_app in HW.
  rewrite <- (app_assoc W1 W2 Z).
  destruct (codon_construct_go b3 b2 b1 b0 e3 e2 s0 s1 done (addr ++ rest) (past N U (W1 ++ W2 ++ Z)) K
              ltac:(lia) Hn) as [Q1 E1].
  destruct (pg_gate 7 e3 e2 s0 s1 (past L (done ++ [e3; e2; s0; s1]) (addr ++ rest)) U W1 (W2 ++ Z) K He
              HW1 ltac:(lia)) as [Q2 E2].
  rewrite table_gate in E2 by exact H32.
  destruct (pa_construct 17 e3 e2 s0 s1 (done ++ [e3; e2; s0; s1]) addr rest
              (U ++ gate_bits (kind_of e3 e2) s0 s1) W2 Z K Ha ltac:(lia)
              ltac:(rewrite length_app; cbn [length]; lia)
              ltac:(rewrite length_app, length_gate_bits; lia)) as [Q3 E3].
  norm_in E2. norm_in Q3. norm_in E3. norm_goal.
  replace 30 with (4 + (8 + 18)) by reflexivity.
  exact (chain 4 (8 + 18) _ _ _ (conj Q1 E1) (chain 8 18 _ _ _ (conj Q2 E2) (conj Q3 E3))).
Qed.

Lemma seg_esc : forall b3 b2 b1 b0 s0 s1 lit addr rest done U W Z K,
  s0 && s1 = false -> length lit = 8 -> length addr = 18 -> length W = 26 -> length done + 30 <= L ->
  length U + 26 <= N ->
  quiet 30 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (true :: true :: s0 :: s1 :: lit ++ addr ++ rest))
                (past N U (W ++ Z)) K)
  /\ dsteps 30 (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (true :: true :: s0 :: s1 :: lit ++ addr ++ rest))
                    (past N U (W ++ Z)) K)
     = mkD (mkC PC 3 true true s0 s1 false) (past L (done ++ true :: true :: s0 :: s1 :: lit ++ addr) rest)
           (past N (U ++ lit ++ addr) Z) K.
Proof.
  intros b3 b2 b1 b0 s0 s1 lit addr rest done U W Z K Hs Hl Ha HW Hd HU.
  assert (He : is_esc true true s0 s1 = true) by (unfold is_esc; cbn [andb]; rewrite Hs; reflexivity).
  assert (Hn : is_end true true s0 s1 = false) by (unfold is_end; cbn [andb]; exact Hs).
  destruct (split_at W 8 ltac:(lia)) as (W1 & W2 & -> & HW1). rewrite length_app in HW.
  rewrite <- (app_assoc W1 W2 Z).
  destruct (codon_construct_go b3 b2 b1 b0 true true s0 s1 done (lit ++ addr ++ rest) (past N U (W1 ++ W2 ++ Z)) K
              ltac:(lia) Hn) as [Q1 E1].
  destruct (pg_esc_construct 7 true true s0 s1 (done ++ [true; true; s0; s1]) lit (addr ++ rest) U W1 (W2 ++ Z) K
              He Hl HW1 ltac:(rewrite length_app; cbn [length]; lia) ltac:(lia)) as [Q2 E2].
  destruct (pa_construct 17 true true s0 s1 ((done ++ [true; true; s0; s1]) ++ lit) addr rest (U ++ lit) W2 Z K
              Ha ltac:(lia) ltac:(rewrite !length_app; cbn [length]; lia) ltac:(rewrite length_app; lia)) as [Q3 E3].
  norm_in E2. norm_in Q3. norm_in E3. norm_goal.
  replace 30 with (4 + (8 + 18)) by reflexivity.
  exact (chain 4 (8 + 18) _ _ _ (conj Q1 E1) (chain 8 18 _ _ _ (conj Q2 E2) (conj Q3 E3))).
Qed.

Lemma seg_copy_gate : forall b3 b2 b1 b0 e3 e2 s0 s1 addr rest done A V W C,
  e3 && e2 = false -> length addr = 18 -> length W = 22 -> length done + 22 <= L -> length V + 22 <= L ->
  quiet 22 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (e3 :: e2 :: s0 :: s1 :: addr ++ rest)) A
                (past L V (W ++ C)))
  /\ dsteps 22 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (e3 :: e2 :: s0 :: s1 :: addr ++ rest)) A
                    (past L V (W ++ C)))
     = mkD (mkC PC 3 e3 e2 s0 s1 true) (past L (done ++ e3 :: e2 :: s0 :: s1 :: addr) rest) A
           (past L (V ++ e3 :: e2 :: s0 :: s1 :: addr) C).
Proof.
  intros b3 b2 b1 b0 e3 e2 s0 s1 addr rest done A V W C H32 Ha HW Hd HV.
  assert (He : is_esc e3 e2 s0 s1 = false) by (unfold is_esc; rewrite H32; reflexivity).
  assert (Hn : is_end e3 e2 s0 s1 = false) by (unfold is_end; rewrite H32; reflexivity).
  destruct W as [|w1 [|w2 [|w3 [|w4 W]]]]; cbn [length] in HW; try lia.
  destruct (codon_copy_go b3 b2 b1 b0 e3 e2 s0 s1 done (addr ++ rest) A V w1 w2 w3 w4 (W ++ C)
              ltac:(lia) ltac:(lia) Hn) as [Q1 E1].
  rewrite He in E1.
  destruct (pa_copy 17 e3 e2 s0 s1 (done ++ [e3; e2; s0; s1]) addr rest A (V ++ [e3; e2; s0; s1]) W C Ha
              ltac:(lia) ltac:(rewrite length_app; cbn [length]; lia) ltac:(rewrite length_app; cbn [length]; lia))
    as [Q2 E2].
  norm_in E2.
  replace 22 with (4 + 18) by reflexivity.
  exact (chain 4 18 _ _ _ (conj Q1 E1) (conj Q2 E2)).
Qed.

Lemma seg_copy_esc : forall b3 b2 b1 b0 s0 s1 lit addr rest done A V W C,
  s0 && s1 = false -> length lit = 8 -> length addr = 18 -> length W = 30 -> length done + 30 <= L ->
  length V + 30 <= L ->
  quiet 30 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (true :: true :: s0 :: s1 :: lit ++ addr ++ rest)) A
                (past L V (W ++ C)))
  /\ dsteps 30 (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (true :: true :: s0 :: s1 :: lit ++ addr ++ rest)) A
                    (past L V (W ++ C)))
     = mkD (mkC PC 3 true true s0 s1 true) (past L (done ++ true :: true :: s0 :: s1 :: lit ++ addr) rest) A
           (past L (V ++ true :: true :: s0 :: s1 :: lit ++ addr) C).
Proof.
  intros b3 b2 b1 b0 s0 s1 lit addr rest done A V W C Hs Hl Ha HW Hd HV.
  assert (He : is_esc true true s0 s1 = true) by (unfold is_esc; cbn [andb]; rewrite Hs; reflexivity).
  assert (Hn : is_end true true s0 s1 = false) by (unfold is_end; cbn [andb]; exact Hs).
  destruct W as [|w1 [|w2 [|w3 [|w4 W]]]]; cbn [length] in HW; try lia.
  destruct (split_at W 8 ltac:(lia)) as (W1 & W2 & -> & HW1). rewrite length_app in HW.
  destruct (codon_copy_go b3 b2 b1 b0 true true s0 s1 done (lit ++ addr ++ rest) A V w1 w2 w3 w4 ((W1 ++ W2) ++ C)
              ltac:(lia) ltac:(lia) Hn) as [Q1 E1].
  rewrite He in E1. norm_in Q1. norm_in E1.
  destruct (pg_esc_copy 7 true true s0 s1 (done ++ [true; true; s0; s1]) lit (addr ++ rest) A
              (V ++ [true; true; s0; s1]) W1 (W2 ++ C) He Hl HW1 ltac:(rewrite length_app; cbn [length]; lia)
              ltac:(rewrite length_app; cbn [length]; lia)) as [Q2 E2].
  destruct (pa_copy 17 true true s0 s1 ((done ++ [true; true; s0; s1]) ++ lit) addr rest A
              ((V ++ [true; true; s0; s1]) ++ lit) W2 C Ha ltac:(lia) ltac:(rewrite !length_app; cbn [length]; lia)
              ltac:(rewrite !length_app; cbn [length]; lia)) as [Q3 E3].
  norm_in E2. norm_in Q3. norm_in E3. norm_goal.
  replace 30 with (4 + (8 + 18)) by reflexivity.
  exact (chain 4 (8 + 18) _ _ _ (conj Q1 E1) (chain 8 18 _ _ _ (conj Q2 E2) (conj Q3 E3))).
Qed.

(* ---- the description read in construct mode ------------------------------------------------- *)
Lemma construct_phase : forall f rest Xr done tail U Z K b3 b2 b1 b0,
  translate_aux f rest = Some Xr -> length done + length rest <= L ->
  length U + length Xr <= N -> length Xr <= length Z ->
  exists nrec, length Xr = 26 * nrec
    /\ quiet (30 * nrec + 4) (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (rest ++ tail)) (past N U Z) K)
    /\ dsteps (30 * nrec + 4) (mkD (mkC PC 3 b3 b2 b1 b0 false) (past L done (rest ++ tail)) (past N U Z) K)
       = mkD (mkC PC 3 true true true true true) (past L [] (done ++ rest ++ tail))
             (past N (U ++ Xr) (skipn (length Xr) Z)) K.
Proof.
  induction f as [|f IH]; intros rest Xr done tail U Z K b3 b2 b1 b0 Ht Hd HU HZ; [discriminate|].
  destruct rest as [|e3 [|e2 [|s0 [|s1 rest1]]]]; try discriminate.
  rewrite translate_aux_S in Ht.
  destruct (e3 && e2) eqn:E32.
  - apply andb_prop in E32 as [-> ->].
    destruct (s0 && s1) eqn:Es.
    + (* the end codon *)
      destruct rest1; [|discriminate]. apply some_inj in Ht. subst Xr.
      apply andb_prop in Es as [-> ->].
      exists 0. split; [reflexivity|]. rewrite app_nil_r.
      cbn [length] in Hd. exact (codon_construct_end b3 b2 b1 b0 done tail (past N U Z) K ltac:(lia)).
    + (* an escaped record *)
      destruct (Nat.eqb (length rest1) 0) eqn:El; [discriminate|].
      destruct (translate_aux f (skipn 26 rest1)) as [X'|] eqn:Ht'; [|discriminate].
      cbn [option_map] in Ht. apply some_inj in Ht. subst Xr.
      pose proof (translate_aux_long _ _ _ Ht') as Hlong. rewrite length_skipn in Hlong.
      destruct (split_at rest1 8 ltac:(lia)) as (lit & r1 & -> & Hl).
      destruct (split_at r1 18 ltac:(rewrite length_app in Hlong; lia)) as (addr & rest2 & -> & Ha).
      assert (Hs26 : skipn 26 (lit ++ addr ++ rest2) = rest2)
        by (rewrite app_assoc; apply skipn_app_exact; rewrite length_app; lia).
      assert (Hf26 : firstn 26 (lit ++ addr ++ rest2) = lit ++ addr)
        by (rewrite app_assoc; apply firstn_app_exact; rewrite length_app; lia).
      rewrite Hs26 in Ht'. rewrite Hf26 in HU, HZ |- *.
      rewrite !length_app in HU, HZ. cbn [length] in Hd. rewrite !length_app in Hd.
      destruct (split_at Z 26 ltac:(lia)) as (W & Z' & -> & HW).
      destruct (seg_esc b3 b2 b1 b0 s0 s1 lit addr (rest2 ++ tail) done U W Z' K Es Hl Ha HW ltac:(lia) ltac:(lia))
        as [Q1 E1].
      destruct (IH rest2 X' (done ++ true :: true :: s0 :: s1 :: lit ++ addr) tail (U ++ lit ++ addr) Z' K
                  true true s0 s1 Ht' ltac:(rewrite length_app; cbn [length]; rewrite !length_app; lia)
                  ltac:(rewrite !length_app; lia) ltac:(rewrite length_app in HZ; lia)) as (nrec & Hn & Q2 & E2).
      norm_in E2.
      exists (S nrec). split; [rewrite !length_app; lia|].
      assert (Hsk : skipn (length ((lit ++ addr) ++ X')) (W ++ Z') = skipn (length X') Z').
      { replace (length ((lit ++ addr) ++ X')) with (length W + length X') by (rewrite !length_app; lia).
        apply skipn_app_plus. }
      rewrite Hsk. norm_goal.
      replace (30 * S nrec + 4) with (30 + (30 * nrec + 4)) by lia.
      exact (chain 30 (30 * nrec + 4) _ _ _ (conj Q1 E1) (conj Q2 E2)).
  - (* a record named by its gate codon *)
    destruct (translate_aux f (skipn 18 rest1)) as [X'|] eqn:Ht'; [|discriminate].
    cbn [option_map] in Ht. apply some_inj in Ht. subst Xr.
    pose proof (translate_aux_long _ _ _ Ht') as Hlong. rewrite length_skipn in Hlong.
    destruct (split_at rest1 18 ltac:(lia)) as (addr & rest2 & -> & Ha).
    rewrite (skipn_app_exact addr rest2 18 Ha) in Ht'.
    rewrite (firstn_app_exact addr rest2 18 Ha) in HU, HZ |- *.
    change (if e3 then 2 else if e2 then 1 else 0) with (kind_of e3 e2) in HU, HZ |- *.
    rewrite !length_app, length_gate_bits in HU, HZ. cbn [length] in Hd. rewrite length_app in Hd.
    destruct (split_at Z 26 ltac:(lia)) as (W & Z' & -> & HW).
    destruct (seg_gate b3 b2 b1 b0 e3 e2 s0 s1 addr (rest2 ++ tail) done U W Z' K E32 Ha HW ltac:(lia) ltac:(lia))
      as [Q1 E1].
    destruct (IH rest2 X' (done ++ e3 :: e2 :: s0 :: s1 :: addr) tail (U ++ gate_bits (kind_of e3 e2) s0 s1 ++ addr)
                Z' K e3 e2 s0 s1 Ht' ltac:(rewrite length_app; cbn [length]; rewrite ?length_app; lia)
                ltac:(rewrite !length_app, length_gate_bits; lia) ltac:(rewrite length_app in HZ; lia))
      as (nrec & Hn & Q2 & E2).
    norm_in E2.
    exists (S nrec). split; [rewrite !length_app, length_gate_bits; lia|].
    assert (Hsk : skipn (length (gate_bits (kind_of e3 e2) s0 s1 ++ addr ++ X')) (W ++ Z') = skipn (length X') Z').
    { replace (length (gate_bits (kind_of e3 e2) s0 s1 ++ addr ++ X')) with (length W + length X')
        by (rewrite !length_app, length_gate_bits; lia).
      apply skipn_app_plus. }
    rewrite Hsk. norm_goal.
    replace (30 * S nrec + 4) with (30 + (30 * nrec + 4)) by lia.
    exact (chain 30 (30 * nrec + 4) _ _ _ (conj Q1 E1) (conj Q2 E2)).
Qed.

(* ---- the description read again in copy mode ------------------------------------------------- *)
Lemma copy_phase : forall f rest Xr done tail A V Z b3 b2 b1 b0,
  translate_aux f rest = Some Xr -> length done + length rest <= L -> length V + length rest <= L ->
  length rest <= length Z ->
  quiet (length rest - 1) (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (rest ++ tail)) A (past L V Z))
  /\ ho (dout (dsteps (length rest - 1) (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (rest ++ tail)) A
                                            (past L V Z)))) = true
  /\ dsteps (length rest) (mkD (mkC PC 3 b3 b2 b1 b0 true) (past L done (rest ++ tail)) A (past L V Z))
     = mkD (mkC PI 1 true true true true false) (past L (done ++ rest) tail) (mkT (td A) 0)
           (mkT (V ++ rest ++ skipn (length rest) Z) 0).
Proof.
  induction f as [|f IH]; intros rest Xr done tail A V Z b3 b2 b1 b0 Ht Hd HV HZ; [discriminate|].
  destruct rest as [|e3 [|e2 [|s0 [|s1 rest1]]]]; try discriminate.
  rewrite translate_aux_S in Ht.
  destruct (e3 && e2) eqn:E32.
  - apply andb_prop in E32 as [-> ->].
    destruct (s0 && s1) eqn:Es.
    + (* the end codon *)
      destruct rest1; [|discriminate]. apply andb_prop in Es as [-> ->].
      cbn [length] in Hd, HV, HZ.
      destruct Z as [|w1 [|w2 [|w3 [|w4 Z]]]]; cbn [length] in HZ; try lia.
      exact (codon_copy_end b3 b2 b1 b0 done tail A V w1 w2 w3 w4 Z ltac:(lia) ltac:(lia)).
    + (* an escaped record *)
      destruct (Nat.eqb (length rest1) 0) eqn:El; [discriminate|].
      destruct (translate_aux f (skipn 26 rest1)) as [X'|] eqn:Ht'; [|discriminate].
      pose proof (translate_aux_long _ _ _ Ht') as Hlong. rewrite length_skipn in Hlong.
      destruct (split_at rest1 8 ltac:(lia)) as (lit & r1 & -> & Hl).
      destruct (split_at r1 18 ltac:(rewrite length_app in Hlong; lia)) as (addr & rest2 & -> & Ha).
      assert (Hs26 : skipn 26 (lit ++ addr ++ rest2) = rest2)
        by (rewrite app_assoc; apply skipn_app_exact; rewrite length_app; lia).
      rewrite Hs26 in Ht'. pose proof (translate_aux_long _ _ _ Ht') as H4.
      assert (Hlen : length (true :: true :: s0 :: s1 :: lit ++ addr ++ rest2) = 30 + length rest2)
        by (cbn [length]; rewrite !length_app; lia).
      rewrite Hlen in Hd, HV, HZ |- *.
      destruct (split_at Z 30 ltac:(lia)) as (W & Z' & -> & HW).
      destruct (seg_copy_esc b3 b2 b1 b0 s0 s1 lit addr (rest2 ++ tail) done A V W Z' Es Hl Ha HW
                  ltac:(lia) ltac:(lia)) as [Q1 E1].
      destruct (IH rest2 X' (done ++ true :: true :: s0 :: s1 :: lit ++ addr) tail A
                  (V ++ true :: true :: s0 :: s1 :: lit ++ addr) Z' true true s0 s1 Ht'
                  ltac:(rewrite length_app; cbn [length]; rewrite !length_app; lia)
                  ltac:(rewrite length_app; cbn [length]; rewrite !length_app; lia)
                  ltac:(rewrite length_app in HZ; lia)) as (Q2 & H2 & E2).
      norm_in E2.
      assert (Hsk : skipn (30 + length rest2) (W ++ Z') = skipn (length rest2) Z') by (rewrite <- HW; apply skipn_app_plus).
      rewrite Hsk. norm_goal.
      exact (chain_last 30 (length rest2) _ _ _ (conj Q1 E1) (conj Q2 (conj H2 E2)) ltac:(lia)).
  - (* a record named by its gate codon *)
    destruct (translate_aux f (skipn 18 rest1)) as [X'|] eqn:Ht'; [|discriminate].
    pose proof (translate_aux_long _ _ _ Ht') as Hlong. rewrite length_skipn in Hlong.
    destruct (split_at rest1 18 ltac:(lia)) as (addr & rest2 & -> & Ha).
    rewrite (skipn_app_exact addr rest2 18 Ha) in Ht'. pose proof (translate_aux_long _ _ _ Ht') as H4.
    assert (Hlen : length (e3 :: e2 :: s0 :: s1 :: addr ++ rest2) = 22 + length rest2)
      by (cbn [length]; rewrite length_app; lia).
    rewrite Hlen in Hd, HV, HZ |- *.
    destruct (split_at Z 22 ltac:(lia)) as (W & Z' & -> & HW).
    destruct (seg_copy_gate b3 b2 b1 b0 e3 e2 s0 s1 addr (rest2 ++ tail) done A V W Z' E32 Ha HW
                ltac:(lia) ltac:(lia)) as [Q1 E1].
    destruct (IH rest2 X' (done ++ e3 :: e2 :: s0 :: s1 :: addr) tail A (V ++ e3 :: e2 :: s0 :: s1 :: addr) Z'
                e3 e2 s0 s1 Ht' ltac:(rewrite length_app; cbn [length]; rewrite ?length_app; lia)
                ltac:(rewrite length_app; cbn [length]; rewrite ?length_app; lia)
                ltac:(rewrite length_app in HZ; lia)) as (Q2 & H2 & E2).
    norm_in E2.
    assert (Hsk : skipn (22 + length rest2) (W ++ Z') = skipn (length rest2) Z') by (rewrite <- HW; apply skipn_app_plus).
    rewrite Hsk. norm_goal.
    exact (chain_last 22 (length rest2) _ _ _ (conj Q1 E1) (conj Q2 (conj H2 E2)) ltac:(lia)).
Qed.

(* ---- one generation -------------------------------------------------------------------------- *)
(* From phase I, with a description d of the image X at the start of the read tape and whatever the
   arm and the copy tape hold, a generation is one pass of phase I, 30 passes per record of X and 4
   on the end codon in construct mode, and one pass per bit of d in copy mode. Only its last pass
   hands over. The arm then holds X from its first cell and the copy tape d, both heads at cell 0. *)
Theorem generation : forall d X tail R A K zc c3 c2 c1 c0 m,
  translate d = Some X -> td R = d ++ tail -> length d <= L -> length X <= N ->
  exists nrec, length X = 26 * nrec
    /\ quiet (30 * nrec + 4 + length d) (mkD (mkC PI zc c3 c2 c1 c0 m) R A K)
    /\ ho (dout (dsteps (30 * nrec + 4 + length d) (mkD (mkC PI zc c3 c2 c1 c0 m) R A K))) = true
    /\ dsteps (S (30 * nrec + 4 + length d)) (mkD (mkC PI zc c3 c2 c1 c0 m) R A K)
       = mkD (mkC PI 1 true true true true false) (past L d tail)
             (mkT (X ++ repeat false (N - length X)) 0) (mkT (d ++ repeat false (L - length d)) 0).
Proof.
  intros d X tail R A K zc c3 c2 c1 c0 m Ht HR HdL HXN. unfold translate in Ht.
  pose proof (translate_aux_long _ _ _ Ht) as Hd4.
  destruct (pass_PI zc c3 c2 c1 c0 m R A K) as [Q0 E0].
  assert (E0' : dstep (mkD (mkC PI zc c3 c2 c1 c0 m) R A K)
                = mkD (mkC PC 3 c3 c2 c1 c0 false) (past L [] (d ++ tail)) (past N [] (repeat false N))
                      (past L [] (repeat false L))).
  { rewrite E0, HR. unfold past. cbn [length app]. rewrite !Nat.Div0.mod_0_l. reflexivity. }
  destruct (construct_phase (length d) d X [] tail [] (repeat false N) (past L [] (repeat false L)) c3 c2 c1 c0 Ht
              ltac:(cbn [length]; lia) ltac:(cbn [length]; lia) ltac:(rewrite repeat_length; lia))
    as (nrec & Hn & Q1 & E1).
  cbn [app] in E1.
  destruct (copy_phase (length d) d X [] tail (past N X (skipn (length X) (repeat false N))) [] (repeat false L)
              true true true true Ht ltac:(cbn [length]; lia) ltac:(cbn [length]; lia)
              ltac:(rewrite repeat_length; lia)) as (Q2 & H2 & E2).
  cbn [app] in E2.
  assert (Htd : td (past N X (skipn (length X) (repeat false N))) = X ++ repeat false (N - length X))
    by (unfold past; cbn [td]; rewrite skipn_repeat_false; reflexivity).
  rewrite Htd, (skipn_repeat_false (length d) L) in E2.
  destruct (chain_last (1 + (30 * nrec + 4)) (length d) _ _ _
              (chain 1 (30 * nrec + 4) _ _ _ (one _ _ Q0 E0') (conj Q1 E1)) (conj Q2 (conj H2 E2)) ltac:(lia))
    as (Q & H & E).
  exists nrec. split; [exact Hn|].
  replace (1 + (30 * nrec + 4) + length d - 1) with (30 * nrec + 4 + length d) in Q, H by lia.
  replace (1 + (30 * nrec + 4) + length d) with (S (30 * nrec + 4 + length d)) in E by lia.
  exact (conj Q (conj H E)).
Qed.

End Dec.