File size: 24,909 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
 
 
 
 
 
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
(* Within one pass, each head is seen through the cell under it when the pass starts and what the pass
   does to it: the value it writes there, the cells it moves, whether it returns to its origin and
   whether its bank or tape is cleared; the active bank through the index of the record at its head.
   One step of the machine refines one step of this abstract machine. *)
From Stdlib Require Import List Bool Arith ZArith Lia.
Import ListNotations.
From TH Require Import TwoHead Net.

Record ahead := mkH { acur : bool; awr : option bool; amv : nat; arw : bool; acl : bool }.

(* the head is still on its first cell and its store is untouched but for its own write there *)
Definition hok (h : ahead) : bool := Nat.eqb (amv h) 0 && negb (arw h) && negb (acl h).
Definition hval (h : ahead) : bool := match awr h with Some v => v | None => acur h end.
Definition hwrite (h : ahead) (v : bool) : ahead := mkH (acur h) (Some v) (amv h) (arw h) (acl h).
Definition hadv (h : ahead) : ahead := mkH (acur h) (awr h) (S (amv h)) (arw h) (acl h).
Definition hrew (h : ahead) : ahead := mkH (acur h) (awr h) 0 true (acl h).
Definition hclr (h : ahead) : ahead := mkH (acur h) (awr h) (amv h) (arw h) true.

Record ast := mkAS { aw : list bool; aR : ahead; aA : ahead; aK : ahead; ai : nat; aho : bool; bad : bool }.

Definition acell (t : ast) (x : nat) : bool :=
  if Nat.eqb x SINK then false
  else if Nat.eqb x RD then hval (aR t)
  else if Nat.eqb x ARM then hval (aA t)
  else if Nat.eqb x CPY then hval (aK t)
  else wget (aw t) x.

(* an operand with a nonzero weight on a head cell must find the head on its first cell *)
Definition opok (t : ast) (x : nat) (w : Z) : bool :=
  if Z.eqb w 0 then true
  else if Nat.eqb x RD then hok (aR t)
  else if Nat.eqb x ARM then hok (aA t)
  else if Nat.eqb x CPY then hok (aK t)
  else true.

Definition astepres (rs : list rec) (t : ast) (a0 : nat) (w0 : Z) (a1 : nat) (w1 : Z) (ao : nat) (v : bool) : ast :=
  let wn := wnext (aw t) ao v in
  let A1 := if Nat.eqb ao ARM then hwrite (aA t) v else aA t in
  let K1 := if Nat.eqb ao CPY then hwrite (aK t) v else aK t in
  let okw := (if Nat.eqb ao ARM then hok (aA t) else true) && (if Nat.eqb ao CPY then hok (aK t) else true) in
  let R2 := if wget wn RR then hrew (aR t) else if wget wn AR then hadv (aR t) else aR t in
  let A1' := if wget wn CB then hclr A1 else A1 in
  let A2 := if wget wn RA then hrew A1' else if wget wn AA then hadv A1' else A1' in
  let K1' := if wget wn CT then hclr K1 else K1 in
  let K2 := if wget wn RC then hrew K1' else if wget wn AC then hadv K1' else K1' in
  let okho := negb (wget wn HO) || Nat.eqb (S (ai t)) (length rs) in
  mkAS (clearq wn) R2 A2 K2 (S (ai t)) (aho t || wget wn HO)
       (bad t || aho t || negb (opok t a0 w0 && opok t a1 w1 && okw && okho)).

Definition astep (rs : list rec) (t : ast) : ast :=
  match nth_error rs (ai t) with
  | None => mkAS (aw t) (aR t) (aA t) (aK t) (ai t) (aho t) true
  | Some (Rec a0 w0 a1 w1 beta ao) =>
      astepres rs t a0 w0 a1 w1 ao (Z.leb 0 (w0 * b2z (acell t a0) + w1 * b2z (acell t a1) + beta)%Z)
  end.

Fixpoint aiter (n : nat) (rs : list rec) (t : ast) : ast :=
  match n with O => t | S m => aiter m rs (astep rs t) end.

Definition enc (rs : list rec) : list bool := concat (map enc_rec rs).

(* ---- the effect of a pass on a tape and on a bank ---------------------------------------------- *)
Fixpoint iter {A : Type} (n : nat) (f : A -> A) (x : A) : A := match n with O => x | S m => f (iter m f x) end.

Definition tape_eff (L : nat) (h : ahead) (t : tape) : tape :=
  mkT (if acl h then repeat false L else match awr h with Some v => upd (td t) (th t) v | None => td t end)
      (iter (amv h) (succ_mod L) (if arw h then 0 else th t)).

Definition bank_eff (S0 b : nat) (h : ahead) (q : bank) : bank :=
  iter (amv h) (advb S0 b)
       (mkB (if acl h then repeat false (S0 * b) else
               match awr h with Some v => upd (bq q) (bs q * b + bj q) v | None => bq q end)
            (if arw h then 0 else bs q) (if arw h then 0 else bj q)).

(* ---- lists ------------------------------------------------------------------------------------- *)
Lemma upd_length : forall l i v, length (upd l i v) = length l.
Proof. induction l as [|x l IH]; intros [|i] v; cbn; auto. Qed.

Lemma nth_upd_same : forall l i v, i < length l -> nth i (upd l i v) false = v.
Proof. induction l as [|x l IH]; intros [|i] v Hi; cbn in *; try lia; auto. apply IH. lia. Qed.

Lemma nth_upd_other : forall l i j v, i <> j -> nth j (upd l i v) false = nth j l false.
Proof.
  induction l as [|x l IH]; intros i j v Hij; [reflexivity|].
  destruct i as [|i], j as [|j]; cbn; try reflexivity; [lia|]. apply IH. lia.
Qed.

Lemma upd_upd : forall l i v w, upd (upd l i v) i w = upd l i w.
Proof. induction l as [|x l IH]; intros [|i] v w; cbn; f_equal; auto. Qed.

Lemma upd_same : forall l i, upd l i (nth i l false) = l.
Proof. induction l as [|x l IH]; intros [|i]; cbn; f_equal; auto. Qed.

Lemma wget_upd : forall w i v x,
  wget (upd w i v) x = if Nat.eqb x i && Nat.ltb i (length w) then v else wget w x.
Proof.
  unfold wget. induction w as [|y w IH]; intros i v x.
  - simpl. rewrite andb_false_r. destruct x; reflexivity.
  - destruct i as [|i], x as [|x]; simpl; try reflexivity; rewrite IH; reflexivity.
Qed.

Lemma length_wnext : forall w ao v, length (wnext w ao v) = length w.
Proof. intros w ao v; unfold wnext. destruct (Nat.leb ao CPY); [reflexivity | apply upd_length]. Qed.

Lemma length_clearq : forall w, length (clearq w) = length w.
Proof. intro w; unfold clearq. rewrite !upd_length. reflexivity. Qed.

(* the cells from 4 on: two windows agree there *)
Definition agree (w w' : list bool) : Prop := forall x, 4 <= x -> wget w x = wget w' x.

Lemma agree_upd : forall w w' i v, agree w w' -> length w = length w' -> agree (upd w i v) (upd w' i v).
Proof.
  intros w w' i v H Hl x Hx. rewrite !wget_upd, Hl.
  destruct (Nat.eqb x i && Nat.ltb i (length w')); auto.
Qed.

Lemma agree_wnext : forall w w' ao v, agree w w' -> length w = length w' -> agree (wnext w ao v) (wnext w' ao v).
Proof. intros w w' ao v H Hl; unfold wnext. destruct (Nat.leb ao CPY); auto using agree_upd. Qed.

Lemma agree_clearq : forall w w', agree w w' -> length w = length w' -> agree (clearq w) (clearq w').
Proof.
  intros w w' H Hl; unfold clearq.
  repeat (apply agree_upd; [|rewrite ?upd_length; auto]). exact H.
Qed.

Lemma iter_advb_bq : forall S1 b' n q, bq (iter n (advb S1 b') q) = bq q.
Proof.
  intros S1 b' n. induction n as [|n IH]; intro q; [reflexivity|].
  change (bq (advb S1 b' (iter n (advb S1 b') q)) = bq q).
  transitivity (bq (iter n (advb S1 b') q)); [|apply IH].
  set (X := iter n (advb S1 b') q). unfold advb. destruct (Nat.eqb (S (bj X)) b'); reflexivity.
Qed.

(* the arm's moves do not depend on the bits of the bank *)
Lemma iter_advb_mkB : forall S1 b' n X Y s j,
  iter n (advb S1 b') (mkB X s j) = mkB X (bs (iter n (advb S1 b') (mkB Y s j))) (bj (iter n (advb S1 b') (mkB Y s j))).
Proof.
  intros S1 b' n. induction n as [|n IH]; intros X Y s j; [reflexivity|]. cbn [iter].
  rewrite (IH X Y s j). set (Z := iter n (advb S1 b') (mkB Y s j)). unfold advb. cbn [bq bs bj].
  destruct (Nat.eqb (S (bj Z)) b'); reflexivity.
Qed.

Lemma succ_mod_mod : forall n x, 1 <= n -> succ_mod n (x mod n) = S x mod n.
Proof.
  intros n x Hn. pose proof (Nat.mod_upper_bound x n ltac:(lia)) as H.
  rewrite <- Nat.add_1_r, <- Nat.Div0.add_mod_idemp_l. unfold succ_mod.
  destruct (Nat.eqb_spec (S (x mod n)) n) as [E|E].
  - rewrite Nat.add_1_r, E. symmetry. apply Nat.Div0.mod_same.
  - rewrite Nat.add_1_r. symmetry. apply Nat.mod_small. lia.
Qed.

(* ---- one step of the machine, against one step of the abstract machine ------------------------ *)
Section Refine.
Variables (al K S0 L : nat) (rs : list rec) (s0 : st).
Hypotheses (HK : 2 <= K) (HS : 1 <= S0) (HL : 1 <= L) (Hfit : fits al K S0 L s0).

Let k0 := kap s0.
Let i0 := succ_mod K k0.
Let b := recw al.

(* the concrete state s and the abstract state t agree, from the state s0 that started the pass *)
Definition rel (s : st) (t : ast) : Prop :=
  agree (win s) (aw t) /\ length (win s) = 2 ^ al /\ length (aw t) = 2 ^ al
  /\ kap s = (if aho t then i0 else k0)
  /\ length (banks s) = K /\ length (tapes s) = K
  /\ nth k0 (banks s) bank0 = mkB (bq (nth k0 (banks s0) bank0)) (ai t) (bj (nth k0 (banks s0) bank0))
  /\ nth i0 (banks s) bank0 = bank_eff S0 b (aA t) (nth i0 (banks s0) bank0)
  /\ nth k0 (tapes s) tape0 = tape_eff L (aR t) (nth k0 (tapes s0) tape0)
  /\ nth i0 (tapes s) tape0 = tape_eff L (aK t) (nth i0 (tapes s0) tape0)
  /\ (forall x, x < K -> x <> k0 -> x <> i0 -> nth x (banks s) bank0 = nth x (banks s0) bank0)
  /\ (forall x, x < K -> x <> k0 -> x <> i0 -> nth x (tapes s) tape0 = nth x (tapes s0) tape0)
  /\ acur (aR t) = tget (nth k0 (tapes s0) tape0)
  /\ acur (aA t) = bget al (nth i0 (banks s0) bank0)
  /\ acur (aK t) = tget (nth i0 (tapes s0) tape0)
  /\ awr (aR t) = None.

Lemma k0_lt : k0 < K.
Proof. destruct Hfit as (_ & H & _). exact H. Qed.

Lemma i0_lt : i0 < K.
Proof. unfold i0, succ_mod. pose proof k0_lt. destruct (Nat.eqb_spec (S k0) K); lia. Qed.

Lemma i0_k0 : i0 <> k0.
Proof. unfold i0, succ_mod. pose proof k0_lt. destruct (Nat.eqb_spec (S k0) K); lia. Qed.

Lemma bank0_ok : forall x, x < K -> length (bq (nth x (banks s0) bank0)) = S0 * b
  /\ bs (nth x (banks s0) bank0) < S0 /\ bj (nth x (banks s0) bank0) < b.
Proof. intros x Hx. destruct Hfit as (_ & _ & _ & _ & H & _). apply H. exact Hx. Qed.

Lemma tape0_ok : forall x, x < K -> length (td (nth x (tapes s0) tape0)) = L /\ th (nth x (tapes s0) tape0) < L.
Proof. intros x Hx. destruct Hfit as (_ & _ & _ & _ & _ & H). apply H. exact Hx. Qed.

(* reading a head cell of a related state, the head being on its first cell *)
Lemma tget_eff : forall h t0, hok h = true -> th t0 < length (td t0) ->
  tget (tape_eff L h t0) = match awr h with Some v => v | None => tget t0 end.
Proof.
  intros h t0 Hok Ht. unfold hok in Hok. destruct h as [c w m r cl]. cbn [amv arw acl] in Hok.
  destruct m; [|discriminate]. destruct r, cl; try discriminate.
  unfold tape_eff, tget. cbn [acl awr amv arw iter td th]. destruct w; [apply nth_upd_same; exact Ht | reflexivity].
Qed.

Lemma bget_eff : forall h q, hok h = true -> bs q * b + bj q < length (bq q) ->
  bget al (bank_eff S0 b h q) = match awr h with Some v => v | None => bget al q end.
Proof.
  intros h q Hok Hq. unfold hok in Hok. destruct h as [c w m r cl]. cbn [amv arw acl] in Hok.
  destruct m; [|discriminate]. destruct r, cl; try discriminate.
  unfold bank_eff, bget, apos. cbn [acl awr amv arw iter bq bs bj]. fold b.
  destruct w; [apply nth_upd_same; exact Hq | reflexivity].
Qed.

(* the concrete operations on the effect of a head *)
Lemma tape_eff_write : forall h t0 v, hok h = true ->
  mkT (upd (td (tape_eff L h t0)) (th (tape_eff L h t0)) v) (th (tape_eff L h t0)) = tape_eff L (hwrite h v) t0.
Proof.
  intros h t0 v Hok. unfold hok in Hok. destruct h as [c w m r cl]. cbn [amv arw acl] in Hok.
  destruct m; [|discriminate]. destruct r, cl; try discriminate.
  unfold tape_eff, hwrite. cbn [acl awr amv arw iter td th acur]. f_equal. destruct w; [apply upd_upd | reflexivity].
Qed.

Lemma tape_eff_adv : forall h t0, mkT (td (tape_eff L h t0)) (succ_mod L (th (tape_eff L h t0))) = tape_eff L (hadv h) t0.
Proof. intros. reflexivity. Qed.

Lemma tape_eff_rew : forall h t0, mkT (td (tape_eff L h t0)) 0 = tape_eff L (hrew h) t0.
Proof. intros. reflexivity. Qed.

Lemma tape_eff_clr : forall h t0, mkT (repeat false L) (th (tape_eff L h t0)) = tape_eff L (hclr h) t0.
Proof. intros. reflexivity. Qed.

Lemma bank_eff_write : forall h q v, hok h = true ->
  mkB (upd (bq (bank_eff S0 b h q)) (apos al (bank_eff S0 b h q)) v) (bs (bank_eff S0 b h q)) (bj (bank_eff S0 b h q))
  = bank_eff S0 b (hwrite h v) q.
Proof.
  intros h q v Hok. unfold hok in Hok. destruct h as [c w m r cl]. cbn [amv arw acl] in Hok.
  destruct m; [|discriminate]. destruct r, cl; try discriminate.
  unfold bank_eff, hwrite, apos. cbn [acl awr amv arw iter bq bs bj acur]. fold b. f_equal.
  destruct w; [apply upd_upd | reflexivity].
Qed.

Lemma bank_eff_adv : forall h q, advb S0 b (bank_eff S0 b h q) = bank_eff S0 b (hadv h) q.
Proof. intros. reflexivity. Qed.

Lemma bank_eff_rew : forall h q, mkB (bq (bank_eff S0 b h q)) 0 0 = bank_eff S0 b (hrew h) q.
Proof.
  intros [c w m r cl] q. unfold bank_eff, hrew. cbn [acl awr amv arw iter bq bs bj acur].
  rewrite iter_advb_bq. reflexivity.
Qed.

Lemma bank_eff_clr : forall h q,
  mkB (repeat false (S0 * b)) (bs (bank_eff S0 b h q)) (bj (bank_eff S0 b h q)) = bank_eff S0 b (hclr h) q.
Proof.
  intros [c w m r cl] q. unfold bank_eff, hclr. cbn [acl awr amv arw acur].
  symmetry. apply (iter_advb_mkB S0 b m (repeat false (S0 * b))).
Qed.

Lemma eta_bank : forall q, mkB (bq q) (bs q) (bj q) = q.
Proof. intros [x y z]. reflexivity. Qed.

Lemma eta_tape : forall t, mkT (td t) (th t) = t.
Proof. intros [x y]. reflexivity. Qed.

(* the active bank holds the records rs from its first slot *)
Hypothesis Hdec : forall r, In r rs -> decodeA al (enc_recA al r) = r.
Hypothesis Hact : forall a r, nth_error rs a = Some r ->
  firstn b (skipn (a * b) (bq (nth k0 (banks s0) bank0))) = enc_recA al r.
Hypothesis Hrs : length rs <= S0.

Definition relA (s : st) (t : ast) : Prop :=
  agree (win s) (aw t) /\ length (win s) = 2 ^ al /\ length (aw t) = 2 ^ al
  /\ kap s = (if aho t then i0 else k0)
  /\ length (banks s) = K /\ length (tapes s) = K
  /\ nth k0 (banks s) bank0 = mkB (bq (nth k0 (banks s0) bank0)) (ai t mod S0) (bj (nth k0 (banks s0) bank0))
  /\ nth i0 (banks s) bank0 = bank_eff S0 b (aA t) (nth i0 (banks s0) bank0)
  /\ nth k0 (tapes s) tape0 = tape_eff L (aR t) (nth k0 (tapes s0) tape0)
  /\ nth i0 (tapes s) tape0 = tape_eff L (aK t) (nth i0 (tapes s0) tape0)
  /\ (forall x, x < K -> x <> k0 -> x <> i0 -> nth x (banks s) bank0 = nth x (banks s0) bank0)
  /\ (forall x, x < K -> x <> k0 -> x <> i0 -> nth x (tapes s) tape0 = nth x (tapes s0) tape0)
  /\ acur (aR t) = tget (nth k0 (tapes s0) tape0)
  /\ acur (aA t) = bget al (nth i0 (banks s0) bank0)
  /\ acur (aK t) = tget (nth i0 (tapes s0) tape0)
  /\ awr (aR t) = None.

Lemma head_ops_acur : forall h v,
  acur (hwrite h v) = acur h /\ acur (hadv h) = acur h /\ acur (hrew h) = acur h /\ acur (hclr h) = acur h.
Proof. intros. repeat split. Qed.

Lemma step_refines : forall s t,
  relA s t -> ai t < length rs -> aho t = false -> bad (astep rs t) = false ->
  relA (step al K S0 L s) (astep rs t).
Proof.
  intros s t Hrel Hi Hho Hbad. pose proof k0_lt as Hk0. pose proof i0_lt as Hi0. pose proof i0_k0 as Hik.
  destruct Hrel as (Hw & Hlw & Hla & Hkap & HlB & HlT & HA & HI & HR & HC & HoB & HoT & cR & cA & cK & wR).
  rewrite Hho in Hkap.
  destruct (nth_error rs (ai t)) as [r|] eqn:Er; [|apply nth_error_None in Er; lia].
  assert (Hdr : decodeA al (enc_recA al r) = r) by (apply Hdec; eapply nth_error_In; exact Er).
  destruct r as [a0 w0 a1 w1 beta ao].
  (* the abstract step and its checks *)
  unfold astep in Hbad |- *. rewrite Er in Hbad |- *.
  set (va := Z.leb 0 (w0 * b2z (acell t a0) + w1 * b2z (acell t a1) + beta)%Z) in *.
  unfold astepres in Hbad. cbv zeta in Hbad. cbn [bad] in Hbad.
  rewrite Hho in Hbad. apply orb_false_iff in Hbad as [Hb0 Hb]. apply orb_false_iff in Hb0 as [Hb0 _].
  apply negb_false_iff in Hb.
  apply andb_prop in Hb as [Hb Hokho]. apply andb_prop in Hb as [Hb Hokw]. apply andb_prop in Hb as [Hop0 Hop1].
  assert (OkA : Nat.eqb ao ARM = true -> hok (aA t) = true)
    by (intro E; rewrite E in Hokw; apply andb_prop in Hokw as [H _]; exact H).
  assert (OkK : Nat.eqb ao CPY = true -> hok (aK t) = true)
    by (intro E; rewrite E in Hokw; apply andb_prop in Hokw as [_ H]; exact H).
  (* the concrete step reads the record at slot ai t of the active bank *)
  destruct (bank0_ok k0 Hk0) as (Hq0 & _ & _). destruct (bank0_ok i0 Hi0) as (Hqi & Hsi & Hji).
  destruct (tape0_ok k0 Hk0) as (Hd0 & Ht0). destruct (tape0_ok i0 Hi0) as (Hdi & Hti).
  assert (Hslot : slot al (nth (kap s) (banks s) bank0) = enc_recA al (Rec a0 w0 a1 w1 beta ao)).
  { rewrite Hkap, HA. unfold slot. cbn [bq bs]. rewrite Nat.mod_small by lia. apply Hact. exact Er. }
  (* the cells the record reads are those of the abstract state *)
  assert (Hcell : forall a w, opok t a w = true -> (w * b2z (cellof al K s a) = w * b2z (acell t a))%Z).
  { intros a w Ho. unfold opok in Ho. unfold cellof, acell. rewrite Hkap. fold i0.
    destruct (Z.eqb_spec w 0) as [Ew|Ew]; [rewrite Ew; reflexivity|].
    destruct (Nat.eqb_spec a SINK); [reflexivity|].
    destruct (Nat.eqb_spec a RD).
    { rewrite HR, (tget_eff (aR t) _ Ho) by lia. rewrite wR. unfold hval. rewrite wR, cR. reflexivity. }
    destruct (Nat.eqb_spec a ARM).
    { rewrite HI, (bget_eff (aA t) _ Ho) by (rewrite Hqi; unfold b; nia).
      unfold hval. destruct (awr (aA t)); [reflexivity|]. rewrite cA. reflexivity. }
    destruct (Nat.eqb_spec a CPY).
    { rewrite HC, (tget_eff (aK t) _ Ho) by lia.
      unfold hval. destruct (awr (aK t)); [reflexivity|]. rewrite cK. reflexivity. }
    rewrite Hw by (unfold SINK, RD, ARM, CPY in *; lia). reflexivity. }
  assert (Hv : Z.leb 0 (w0 * b2z (cellof al K s a0) + w1 * b2z (cellof al K s a1) + beta)%Z = va).
  { unfold va. rewrite (Hcell a0 w0 Hop0), (Hcell a1 w1 Hop1). reflexivity. }
  unfold step. rewrite Hslot, Hdr. rewrite Hv.
  (* the state after the step *)
  assert (Hag : agree (wnext (win s) ao va) (wnext (aw t) ao va)) by (apply agree_wnext; [exact Hw | congruence]).
  assert (Hq : forall c, 4 <= c -> wget (wnext (win s) ao va) c = wget (wnext (aw t) ao va) c) by (intros; apply Hag; lia).
  unfold stepres, astepres. cbv zeta. rewrite Hkap. fold i0.
  rewrite !Hq by (unfold AR, AA, AC, RR, RA, RC, CB, CT, HO; lia).
  refine (conj _ (conj _ (conj _ (conj _ (conj _ (conj _ (conj _ (conj _ (conj _ (conj _ (conj _ (conj _ _)))))))))))).
  - cbn [win aw]. apply agree_clearq; [exact Hag | rewrite !length_wnext; congruence].
  - cbn [win]. rewrite length_clearq, length_wnext. exact Hlw.
  - cbn [aw]. rewrite length_clearq, length_wnext. exact Hla.
  - cbn [kap aho]. rewrite Hho. cbn [orb]. reflexivity.
  - cbn [banks]. rewrite length_map, length_seq. reflexivity.
  - cbn [tapes]. rewrite length_map, length_seq. reflexivity.
  - (* the active bank *)
    cbn [banks ai]. rewrite (nth_map_seq _ _ K k0 bank0 Hk0), Nat.eqb_refl. rewrite HA. cbn [bq bs bj].
    rewrite succ_mod_mod by lia. reflexivity.
  - (* the idle bank *)
    cbn [banks aA]. rewrite (nth_map_seq _ _ K i0 bank0 Hi0), (proj2 (Nat.eqb_neq i0 k0) Hik), Nat.eqb_refl. rewrite HI.
    assert (HI1 : (if Nat.eqb ao ARM
                   then mkB (upd (bq (bank_eff S0 b (aA t) (nth i0 (banks s0) bank0)))
                              (apos al (bank_eff S0 b (aA t) (nth i0 (banks s0) bank0))) va)
                            (bs (bank_eff S0 b (aA t) (nth i0 (banks s0) bank0)))
                            (bj (bank_eff S0 b (aA t) (nth i0 (banks s0) bank0)))
                   else bank_eff S0 b (aA t) (nth i0 (banks s0) bank0))
                  = bank_eff S0 b (if Nat.eqb ao ARM then hwrite (aA t) va else aA t) (nth i0 (banks s0) bank0)).
    { destruct (Nat.eqb ao ARM) eqn:E; [|reflexivity]. apply bank_eff_write. apply OkA. reflexivity. }
    rewrite HI1. set (A1 := if Nat.eqb ao ARM then hwrite (aA t) va else aA t).
    assert (HI1' : mkB (if wget (wnext (aw t) ao va) CB then repeat false (S0 * recw al) else bq (bank_eff S0 b A1 (nth i0 (banks s0) bank0)))
                       (bs (bank_eff S0 b A1 (nth i0 (banks s0) bank0))) (bj (bank_eff S0 b A1 (nth i0 (banks s0) bank0)))
                   = bank_eff S0 b (if wget (wnext (aw t) ao va) CB then hclr A1 else A1) (nth i0 (banks s0) bank0)).
    { destruct (wget (wnext (aw t) ao va) CB); [apply bank_eff_clr | apply eta_bank]. }
    rewrite HI1'. set (A1' := if wget (wnext (aw t) ao va) CB then hclr A1 else A1).
    destruct (wget (wnext (aw t) ao va) RA); [apply bank_eff_rew|].
    destruct (wget (wnext (aw t) ao va) AA); [apply bank_eff_adv | reflexivity].
  - (* the read tape *)
    cbn [tapes aR]. rewrite (nth_map_seq _ _ K k0 tape0 Hk0), Nat.eqb_refl. rewrite HR.
    destruct (wget (wnext (aw t) ao va) RR); [apply tape_eff_rew|].
    destruct (wget (wnext (aw t) ao va) AR); [apply tape_eff_adv | apply eta_tape].
  - (* the copy tape *)
    cbn [tapes aK]. rewrite (nth_map_seq _ _ K i0 tape0 Hi0), (proj2 (Nat.eqb_neq i0 k0) Hik), Nat.eqb_refl. rewrite HC.
    assert (HC1 : (if Nat.eqb ao CPY
                   then mkT (upd (td (tape_eff L (aK t) (nth i0 (tapes s0) tape0))) (th (tape_eff L (aK t) (nth i0 (tapes s0) tape0))) va)
                            (th (tape_eff L (aK t) (nth i0 (tapes s0) tape0)))
                   else tape_eff L (aK t) (nth i0 (tapes s0) tape0))
                  = tape_eff L (if Nat.eqb ao CPY then hwrite (aK t) va else aK t) (nth i0 (tapes s0) tape0)).
    { destruct (Nat.eqb ao CPY) eqn:E; [|reflexivity]. apply tape_eff_write. apply OkK. reflexivity. }
    rewrite HC1. set (K1 := if Nat.eqb ao CPY then hwrite (aK t) va else aK t).
    assert (HC1' : mkT (if wget (wnext (aw t) ao va) CT then repeat false L else td (tape_eff L K1 (nth i0 (tapes s0) tape0)))
                       (th (tape_eff L K1 (nth i0 (tapes s0) tape0)))
                   = tape_eff L (if wget (wnext (aw t) ao va) CT then hclr K1 else K1) (nth i0 (tapes s0) tape0)).
    { destruct (wget (wnext (aw t) ao va) CT); [apply tape_eff_clr | apply eta_tape]. }
    transitivity (let C1' := tape_eff L (if wget (wnext (aw t) ao va) CT then hclr K1 else K1) (nth i0 (tapes s0) tape0) in
                  mkT (td C1') (if wget (wnext (aw t) ao va) RC then 0
                                else if wget (wnext (aw t) ao va) AC then succ_mod L (th C1') else th C1')).
    { cbv zeta. rewrite <- HC1'. cbn [td th]. reflexivity. }
    cbv zeta. set (K1' := if wget (wnext (aw t) ao va) CT then hclr K1 else K1).
    destruct (wget (wnext (aw t) ao va) RC); [apply tape_eff_rew|].
    destruct (wget (wnext (aw t) ao va) AC); [apply tape_eff_adv | apply eta_tape].
  - (* the other banks *)
    intros x Hx E1 E2. cbn [banks]. rewrite (nth_map_seq _ _ K x bank0 Hx).
    rewrite (proj2 (Nat.eqb_neq x k0) E1), (proj2 (Nat.eqb_neq x i0) E2). apply HoB; assumption.
  - (* the other tapes *)
    intros x Hx E1 E2. cbn [tapes]. rewrite (nth_map_seq _ _ K x tape0 Hx).
    rewrite (proj2 (Nat.eqb_neq x k0) E1), (proj2 (Nat.eqb_neq x i0) E2). apply HoT; assumption.
  - (* the cells under the heads when the pass started, and the read tape never written *)
    cbn [aR aA aK]. refine (conj _ (conj _ (conj _ _))).
    + destruct (wget (wnext (aw t) ao va) RR); [|destruct (wget (wnext (aw t) ao va) AR)]; exact cR.
    + destruct (wget (wnext (aw t) ao va) RA), (wget (wnext (aw t) ao va) AA), (wget (wnext (aw t) ao va) CB),
        (Nat.eqb ao ARM); exact cA.
    + destruct (wget (wnext (aw t) ao va) RC), (wget (wnext (aw t) ao va) AC), (wget (wnext (aw t) ao va) CT),
        (Nat.eqb ao CPY); exact cK.
    + destruct (wget (wnext (aw t) ao va) RR); [|destruct (wget (wnext (aw t) ao va) AR)]; exact wR.
Qed.

Lemma bad_mono : forall n t, bad t = true -> bad (aiter n rs t) = true.
Proof.
  induction n as [|n IH]; intros t H; cbn [aiter]; [exact H|].
  apply IH. unfold astep. destruct (nth_error rs (ai t)) as [[a0 w0 a1 w1 beta ao]|]; [|reflexivity].
  unfold astepres. cbv zeta. cbn [bad]. rewrite H. reflexivity.
Qed.

Lemma astep_clean : forall t, bad (astep rs t) = false -> bad t = false /\ aho t = false.
Proof.
  intros t H. unfold astep in H. destruct (nth_error rs (ai t)) as [[a0 w0 a1 w1 beta ao]|]; [|discriminate].
  unfold astepres in H. cbv zeta in H. cbn [bad] in H.
  apply orb_false_iff in H as [H _]. apply orb_false_iff in H as [H1 H2]. split; assumption.
Qed.

Lemma astep_ai : forall t, ai t < length rs -> ai (astep rs t) = S (ai t).
Proof.
  intros t H. unfold astep. destruct (nth_error rs (ai t)) as [[a0 w0 a1 w1 beta ao]|] eqn:E; [reflexivity|].
  apply nth_error_None in E. lia.
Qed.

Lemma aiter_ai : forall n t, ai t + n <= length rs -> ai (aiter n rs t) = ai t + n.
Proof.
  induction n as [|n IH]; intros t H; cbn [aiter]; [lia|]. rewrite IH; rewrite ?astep_ai; lia.
Qed.

(* a pass of the machine refines the abstract pass, as long as the abstract pass is not bad *)
Lemma pass_refines : forall n s t, relA s t -> ai t + n <= length rs -> bad (aiter n rs t) = false ->
  relA (itern al K S0 L n s) (aiter n rs t).
Proof.
  induction n as [|n IH]; intros s t Hrel Hn Hbad; [exact Hrel|].
  cbn [itern aiter] in *.
  assert (Hb1 : bad (astep rs t) = false).
  { destruct (bad (astep rs t)) eqn:E; [|reflexivity]. rewrite (bad_mono n _ E) in Hbad. discriminate. }
  destruct (astep_clean t Hb1) as [_ Hho].
  apply IH; [apply step_refines; auto; lia | rewrite astep_ai; lia | exact Hbad].
Qed.

End Refine.