]> matita.cs.unibo.it Git - helm.git/blob - matita/matita/lib/turing/multi_universal/unistep.ma
919e684f0fc80c109679f43560907c52efd22d97
[helm.git] / matita / matita / lib / turing / multi_universal / unistep.ma
1 (*
2     ||M||  This file is part of HELM, an Hypertextual, Electronic   
3     ||A||  Library of Mathematics, developed at the Computer Science 
4     ||T||  Department of the University of Bologna, Italy.           
5     ||I||                                                            
6     ||T||  
7     ||A||  
8     \   /  This file is distributed under the terms of the       
9      \ /   GNU General Public License Version 2   
10       V_____________________________________________________________*)
11
12
13 include "turing/multi_universal/unistep_aux.ma".
14
15 definition exec_move ≝ 
16   cfg_to_obj · tape_move_obj · restart_tape prg 2 · obj_to_cfg.
17
18 definition R_exec_move ≝ λt1,t2:Vector (tape FSUnialpha) 3.
19 ∀c,m,ls1,ls2,rs2.
20   nth cfg ? t1 (niltape ?) = mk_tape FSUnialpha (c::ls1@[bar]) (None ?) [ ] → 
21   nth prg ? t1 (niltape ?) = midtape FSUnialpha (ls2@[bar]) m rs2 →
22   only_bits (list_of_tape ? (nth obj ? t1 (niltape ?))) →
23   c ≠ bar → m ≠ bar →
24   let new_obj ≝ 
25       tape_move_mono ? (nth obj ? t1 (niltape ?)) 
26         〈char_to_bit_option c, char_to_move m〉 in
27   let next_c ≝ low_char' (current ? new_obj) in 
28   let new_cfg ≝ midtape ? [ ] bar ((reverse ? ls1)@[next_c]) in 
29   let new_prg ≝ midtape FSUnialpha [ ] bar ((reverse ? ls2)@m::rs2) in
30   t2 = Vector_of_list ? [new_obj;new_cfg;new_prg].
31
32
33 lemma sem_exec_move: exec_move ⊨ R_exec_move.
34 @(sem_seq_app ??????? sem_cfg_to_obj1
35   (sem_seq ?????? sem_tape_move_obj
36    (sem_seq ?????? (sem_restart_tape ???) sem_obj_to_cfg1))) //
37 #ta #tout * #t1 * #semM1 * #t2 * #semM2 * #t3 * #semM3 #semM4 
38 #c #m #ls1 #ls2 #rs2 #Hcfg #Hprg #Honlybits #Hc #Hm 
39 (* M1 = cfg_to_obj *)
40 lapply (semM1 … Hcfg Hc) #Ht1 
41 (* M2 = tape_move *)
42 whd in semM2; >Ht1 in semM2; -Ht1
43 >nth_change_vec_neq [2:@eqb_false_to_not_eq %] 
44 >nth_change_vec_neq [2:@eqb_false_to_not_eq %] 
45 >Hprg #Ht2 lapply (Ht2 … (refl ??)) -Ht2
46 >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
47 >nth_change_vec // >change_vec_commute [2:@eqb_false_to_not_eq %]
48 >change_vec_change_vec #Ht2 
49 (* M3 = restart prg *) 
50 whd in semM3; >Ht2 in semM3; #semM3 lapply (semM3 … (refl ??)); -semM3
51 >nth_change_vec_neq [2:@eqb_false_to_not_eq %] 
52 >nth_change_vec_neq [2:@eqb_false_to_not_eq %] #Ht3
53 (* M4 = obj_to_cfg *) 
54 whd in semM4; >Ht3 in semM4; 
55 >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
56 >nth_change_vec [2:@leb_true_to_le %] #semM4 lapply (semM4 … (refl ??)) -semM4
57 >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
58 >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
59 >nth_change_vec [2:@leb_true_to_le %] #semM4 >(semM4 ?)
60   [(* tape by tape *)
61    @(eq_vec … (niltape ?)) #i #lei2 
62    cases (le_to_or_lt_eq … (le_S_S_to_le …lei2))
63     [#lei1 cases (le_to_or_lt_eq … (le_S_S_to_le …lei1))
64       [#lei0 lapply(le_n_O_to_eq … (le_S_S_to_le …lei0)) #eqi <eqi
65        >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
66        >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
67        >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
68        >nth_change_vec [2:@leb_true_to_le %] %
69       |#Hi >Hi (* obj tape *)
70        >nth_change_vec [2:@leb_true_to_le %] whd in ⊢ (???%);
71        >reverse_cons >reverse_append >reverse_single 
72        whd in match (option_hd ??); whd in match (tail ??);
73        whd in ⊢ (??%?); %
74       ]
75     |#Hi >Hi (* prg tape *)
76      >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
77      >nth_change_vec [2:@leb_true_to_le %] whd in ⊢ (???%);
78      >Hprg whd in match (list_of_tape ??); >reverse_append
79      >reverse_single % 
80     ]
81   |#b #Hcurrent @(list_of_tape_write ? is_bit … (char_to_bit_option c) ? Honlybits)
82     [#b0 cases c
83       [#b1 whd in ⊢ (??%?→?); #Hbit destruct (Hbit) %
84       |whd in ⊢ (??%?→?); #Hbit destruct (Hbit)
85       |whd in ⊢ (??%?→?); #Hbit destruct (Hbit)
86       ]
87     |>(list_of_tape_move … (char_to_move m)) @current_in_list @Hcurrent
88     ]
89   ]
90 qed.
91        
92 definition unistep ≝ 
93   match_m cfg prg FSUnialpha 2 · 
94   restart_tape cfg 2 · mmove cfg ? 2 R · copy prg cfg FSUnialpha 2 ·
95   exec_move.
96
97 (*
98 definition legal_tape ≝ λn,l,h,t.
99   ∃state,char,table.
100   nth cfg ? t1 (niltape ?) = midtape ? [ ] bar (state@[char]) →
101   is_config n (bar::state@[char]) →  
102   nth prg ? t1 (niltape ?) = midtape ? [ ] bar table →
103   bar::table = table_TM n l h → *)
104
105 definition R_unistep ≝ λn,l,h.λt1,t2: Vector ? 3.
106   ∀state,char,table.
107   (* cfg *)
108   nth cfg ? t1 (niltape ?) = midtape ? [ ] bar (state@[char]) →
109   is_config n (bar::state@[char]) →  
110   (* prg *)
111   nth prg ? t1 (niltape ?) = midtape ? [ ] bar table →
112   bar::table = table_TM n l h →
113   (* obj *)
114   only_bits (list_of_tape ? (nth obj ? t1 (niltape ?))) →
115   let conf ≝ (bar::state@[char]) in
116   (∃ll,lr.bar::table = ll@conf@lr) →
117 (*
118     ∃nstate,nchar,m,t. tuple_encoding n h t = (conf@nstate@[nchar;m]) ∧ 
119     mem ? t l ∧  *)
120     ∀nstate,nchar,m,t. 
121     tuple_encoding n h t = (conf@nstate@[nchar;m])→ 
122     mem ? t l →
123     let new_obj ≝ 
124      tape_move_mono ? (nth obj ? t1 (niltape ?)) 
125        〈char_to_bit_option nchar,char_to_move m〉 in
126     let next_char ≝ low_char' (current ? new_obj) in
127     t2 = 
128       change_vec ??
129         (change_vec ?? t1 (midtape ? [ ] bar (nstate@[next_char])) cfg)
130         new_obj obj.
131         
132 lemma lt_obj : obj < 3. // qed.
133 lemma lt_cfg : cfg < 3. // qed.
134 lemma lt_prg : prg < 3. // qed.
135
136 definition R_copy_strict ≝ 
137   λsrc,dst,sig,n.λint,outt: Vector (tape sig) (S n).
138   ((current ? (nth src ? int (niltape ?)) = None ? ∨
139     current ? (nth dst ? int (niltape ?)) = None ?) → outt = int) ∧
140   (∀ls,x,x0,rs,ls0,rs0. 
141     nth src ? int (niltape ?) = midtape sig ls x rs →
142     nth dst ? int (niltape ?) = midtape sig ls0 x0 rs0 →
143     |rs0| ≤ |rs| → 
144     (∃rs1,rs2.rs = rs1@rs2 ∧ |rs1| = |rs0| ∧
145      outt = change_vec ?? 
146             (change_vec ?? int  
147               (mk_tape sig (reverse sig rs1@x::ls) (option_hd sig rs2)
148             (tail sig rs2)) src)
149             (mk_tape sig (reverse sig rs1@x::ls0) (None sig) []) dst)).
150
151 lemma sem_copy_strict : ∀src,dst,sig,n. src ≠ dst → src < S n → dst < S n → 
152   copy src dst sig n ⊨ R_copy_strict src dst sig n.
153 #src #dst #sig #n #Hneq #Hsrc #Hdst @(Realize_to_Realize … (sem_copy …)) //
154 #ta #tb * #Htb1 #Htb2 % [ @Htb1 ]
155 #ls #x #x0 #rs #ls0 #rs0 #Htamid_src #Htamid_dst #Hlen
156 cases (Htb2 … Htamid_src Htamid_dst) -Htb1 -Htb2
157 [ * #rs1 * #rs2 * * #Hrs0 #Heq #Htb <Heq in Hlen; >Hrs0 >length_append
158   >(plus_n_O (|rs1|)) #Hlen cut (|rs2| ≤ 0) [ /2 by le_plus_to_le/ ]
159   #Hlenrs2 cut (rs2 = [ ]) 
160   [ cases rs2 in Hlenrs2; // #r3 #rs3 normalize #H @False_ind cases (not_le_Sn_O (|rs3|)) /2/ ]
161   #Hrs2 destruct (Hrs2) >append_nil in Hrs0; #Hrs0 destruct (Hrs0) -Hlenrs2 -Hlen
162   <plus_n_O <plus_n_O %{rs} %{[ ]} >append_nil % [ % // ] @Htb
163 | * #rs1 * #rs2 #H %{rs1} %{rs2} @H ]
164 qed.
165
166 axiom daemon : ∀P:Prop.P.
167
168 lemma sem_unistep : ∀n,l,h.unistep ⊨ R_unistep n l h.
169 #n #l #h
170 @(sem_seq_app ??????? (sem_match_m cfg prg FSUnialpha 2 ???)
171   (sem_seq ?????? (sem_restart_tape ???)
172    (sem_seq ?????? (sem_move_multi ? 2 cfg R ?)
173     (sem_seq ?????? (sem_copy_strict prg cfg FSUnialpha 2 ???)
174      (sem_exec_move …)))))
175   /2 by le_n,sym_not_eq/
176 #ta #tb #HR #state #char #table #Hta_cfg #Hcfg #Hta_prg #Htable
177 #Hbits_obj #Htotaltable
178 #nstate #nchar #m #t #Htuple #Hmatch
179 cases HR -HR #tc * whd in ⊢ (%→?); 
180 >Hta_cfg #H cases (H ?? (refl ??)) -H 
181 (* prg starts with a bar, so it's not empty *) #_
182 >Hta_prg #H lapply (H ??? (refl ??)) -H *
183 [| cases Htotaltable #ll * #lr #H >H 
184    #Hfalse @False_ind cases (Hfalse ll lr) #H1 @H1 //]
185 * #ll * #lr * #Hintable -Htotaltable #Htc
186 * #td * whd in ⊢ (%→?); >Htc
187 >nth_change_vec_neq [|@sym_not_eq //] >(nth_change_vec ?????? lt_cfg)
188 #Htd lapply (Htd ? (refl ??)) -Htd
189 >change_vec_commute [|@sym_not_eq //] >change_vec_change_vec
190 >(?: list_of_tape ? (mk_tape ? (reverse ? (state@[char])@[bar]) (None ?) [ ]) =
191      bar::state@[char]) 
192 [|whd in ⊢ (??%?); >left_mk_tape >reverse_append >reverse_reverse
193   >current_mk_tape >right_mk_tape [| #_ %2 % ] normalize >append_nil % ]
194 whd in ⊢ (???(???(????%?)??)→?); whd in match (tail ??); #Htd
195 (* move cfg to R *)
196 * #te * whd in ⊢ (%→?); >Htd
197 >change_vec_commute [|@sym_not_eq //] >change_vec_change_vec
198 >nth_change_vec_neq [|@sym_not_eq //] >nth_change_vec //
199 >Htable in Hintable; #Hintable #Hte
200 (* copy *)
201 lapply (cfg_in_table_to_tuple ???? Hcfg ?? Hintable)
202 * #newconfig * #m0 * #lr0 * * #Hlr destruct (Hlr) #Hnewcfg #Hm0
203 cut (∃fo,so.state = fo::so ∧ |so| = n)
204 [ @daemon ] * #fo * #so * #Hstate_exp #Hsolen
205 cut (∃fn,sn,cn.newconfig = fn::sn@[cn] ∧ |sn| = n)
206 [ @daemon ] * #fn * #sn * #cn * #Hnewstate_exp #Hsnlen
207 * #tf * * #_ >Hte >(nth_change_vec ?????? lt_prg)
208 >nth_change_vec_neq [|@sym_not_eq //] >(nth_change_vec ?????? lt_cfg)
209 >Hstate_exp >Hnewstate_exp
210 whd in match (mk_tape ????); whd in match (tape_move ???);
211 #Htf cases (Htf ?????? (refl ??) (refl ??) ?) -Htf
212 [| whd in match (tail ??); >length_append >length_append 
213    >Hsolen >length_append >Hsnlen //]
214 #rs1 * #rs2 whd in match (tail ??); * *
215 #Hrs1rs2 #Hrs1len
216 >change_vec_change_vec >change_vec_commute [|@sym_not_eq //]
217 >change_vec_change_vec >append_nil #Htf 
218 (* exec_move *)
219 cut ((sn@[cn])=rs1)
220   [@(append_l1_injective ?????? Hrs1rs2) >Hrs1len 
221    >length_append >length_append normalize >Hsolen >Hsnlen % ] #Hrs1  
222 cut (m0::lr0=rs2) [@(append_l2_injective ?????? Hrs1rs2) >Hrs1 % ] #Hrs2 
223 cut (∃ll1. ll@[bar] = bar::ll1) 
224   [@daemon (* ll is at the begininng of a table *)] * #ll1 #Hll
225 whd in ⊢ (%→?); >Htf >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
226 >nth_change_vec [2:@leb_true_to_le %] 
227 >nth_change_vec [2:@leb_true_to_le %]
228 >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
229 >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
230 >append_cons <Hrs1 >reverse_append >reverse_single 
231 <Hrs2 >(append_cons … bar ll) >Hll >reverse_cons
232 #sem_exec_move 
233 lapply
234   (sem_exec_move ? m0 ?
235     (([cn]@reverse FSUnialpha sn)
236           @fn::reverse FSUnialpha (ll1@(fo::so)@[char])) lr0 … (refl ??) ????) 
237   [@Hm0 
238   |@daemon (* OK *)
239   |@Hbits_obj
240   |whd in ⊢ (??%?); >associative_append >associative_append 
241    >associative_append %
242   |#Htb >Htb @(eq_vec … (niltape ?)) (* tape by tape *) #i #lei2 
243    cases (le_to_or_lt_eq … (le_S_S_to_le …lei2))
244     [#lei1 cases (le_to_or_lt_eq … (le_S_S_to_le …lei1))
245       [#lei0 lapply(le_n_O_to_eq … (le_S_S_to_le …lei0)) #eqi <eqi
246        (* obj tape *)
247        >nth_change_vec [2:@leb_true_to_le %] 
248        (* dimostrare che la tabella e' univoca
249           da cui m = m0 e nchar = cn *)
250       |(* cfg tape *) #eqi >eqi
251        >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
252        >nth_change_vec [2:@leb_true_to_le %] 
253        (* idem *)
254       ]
255     |(* prg tape *) #eqi >eqi
256       >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
257       >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
258       >Hta_prg whd in ⊢ (??%?); @eq_f @(cons_injective_r ? bar bar)
259       >Htable >Hintable >reverse_append >reverse_cons
260       >reverse_reverse >reverse_cons >reverse_reverse
261       >associative_append >associative_append >associative_append
262       >(append_cons ? bar ll) >Hll @eq_f @eq_f <Hstate_exp @eq_f
263       >Hnewstate_exp %
264     ]
265   ]
266   
267   
268 qed.
269
270
271
272   cut ((mk_tape FSUnialpha []
273      (option_hd FSUnialpha
274       (reverse FSUnialpha (m0::[]@reverse FSUnialpha (sn@[cn])@[fn; bar])))
275      (tail FSUnialpha
276       (reverse FSUnialpha (m0::[]@reverse FSUnialpha (sn@[cn])@[fn; bar])))) =
277       midtape ? [ ] bar (fn::sn@[cn;m0]))
278   [cut (reverse FSUnialpha (m0::[]@reverse FSUnialpha (sn@[cn])@[fn; bar]) =
279           bar::fn::sn@[cn;m0])
280     [>reverse_cons whd in ⊢ (??(??(??%)?)?); >reverse_append >reverse_reverse
281      >append_cons in ⊢ (???%); % ] #Hrev >Hrev % ] #Hmk_tape >Hmk_tape -Hmk_tape
282    >change_vec_commute
283
284   >reverse_append >reverse_append
285   check reverse_cons
286   <reverse_cons >reverse_cons
287    -Htg #Htg 
288
289 >(change_vec_commute ????? cfg prg) [2:@eqb_false_to_not_eq %]
290 >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
291 >nth_change_vec_neq [2:@eqb_false_to_not_eq %]
292 lapply (append_l1_injective ?????? Hrs1rs2)
293 [ >Hsnlen >Hrs1len >length_append >length_append >length_append >length_append
294   normalize >Hsolen >Hsnlen % ]
295 #Hrs1 <Hrs1 >reverse_append #Htg cases (Htg ?? (refl ??)) -Htg
296 cases m0
297   [#mv #_ #Htg #_
298
299    
300       
301       
302
303 [ * 
304  
305   match_m cfg prg FSUnialpha 2 ·
306   restart_tape cfg · copy prg cfg FSUnialpha 2 ·
307   cfg_to_obj · tape_move_obj · restart_tape prg · obj_to_cfg.
308
309 definition tape_map ≝ λA,B:FinSet.λf:A→B.λt.
310   mk_tape B (map ?? f (left ? t)) 
311     (option_map ?? f (current ? t)) 
312     (map ?? f (right ? t)).
313     
314 lemma map_list_of_tape: ∀A,B,f,t.
315   list_of_tape B (tape_map ?? f t) = map ?? f (list_of_tape A t).
316 #A #B #f * // normalize // #ls #c #rs <map_append %
317 qed.
318
319 lemma low_char_current : ∀t.
320   low_char' (current FSUnialpha (tape_map FinBool FSUnialpha bit t))
321   = low_char (current FinBool t).
322 * // qed.
323
324 definition low_tapes: ∀M:normalTM.∀c:nconfig (no_states M).Vector ? 3 ≝ 
325 λM:normalTM.λc:nconfig (no_states M).Vector_of_list ?
326   [tape_map ?? bit (ctape ?? c);
327    midtape ? [ ] bar 
328     ((bits_of_state ? (nhalt M) (cstate ?? c))@[low_char (current ? (ctape ?? c))]);
329    midtape ? [ ] bar (tail ? (table_TM ? (graph_enum ?? (ntrans M)) (nhalt M)))
330   ].
331
332 lemma obj_low_tapes: ∀M,c.
333   nth obj ? (low_tapes M c) (niltape ?) = tape_map ?? bit (ctape ?? c).
334 // qed.
335
336 lemma cfg_low_tapes: ∀M,c.
337   nth cfg ? (low_tapes M c) (niltape ?) = 
338   midtape ? [ ] bar 
339     ((bits_of_state ? (nhalt M) (cstate ?? c))@[low_char (current ? (ctape ?? c))]).
340 // qed.
341
342 lemma prg_low_tapes: ∀M,c.
343   nth prg ? (low_tapes M c) (niltape ?) = 
344   midtape ? [ ] bar (tail ? (table_TM ? (graph_enum ?? (ntrans M)) (nhalt M))).
345 // qed.
346
347 (* commutation lemma for write *)
348 lemma map_write: ∀t,cout.
349  tape_write ? (tape_map FinBool ? bit t) (char_to_bit_option (low_char cout))
350   = tape_map ?? bit (tape_write ? t cout).
351 #t * // #b whd in match (char_to_bit_option ?);
352 whd in ⊢ (??%%); @eq_f3 [elim t // | // | elim t //]
353 qed.
354
355 (* commutation lemma for moves *)
356 lemma map_move: ∀t,m.
357  tape_move ? (tape_map FinBool ? bit t) (char_to_move (low_mv m))
358   = tape_map ?? bit (tape_move ? t m).
359 #t * // whd in match (char_to_move ?);
360   [cases t // * // | cases t // #ls #a * //]
361 qed.
362   
363 (* commutation lemma for actions *)
364 lemma map_action: ∀t,cout,m.
365  tape_move ? (tape_write ? (tape_map FinBool ? bit t)
366     (char_to_bit_option (low_char cout))) (char_to_move (low_mv m)) 
367  = tape_map ?? bit (tape_move ? (tape_write ? t cout) m).
368 #t #cout #m >map_write >map_move % 
369 qed. 
370
371 lemma map_move_mono: ∀t,cout,m.
372  tape_move_mono ? (tape_map FinBool ? bit t)
373   〈char_to_bit_option (low_char cout), char_to_move (low_mv m)〉
374  = tape_map ?? bit (tape_move_mono ? t 〈cout,m〉).
375 @map_action
376 qed. 
377
378 definition R_unistep_high ≝ λM:normalTM.λt1,t2.
379 ∀c:nconfig (no_states M).
380   t1 = low_tapes M c → 
381   t2 = low_tapes M (step ? M c). 
382
383 lemma R_unistep_equiv : ∀M,t1,t2. 
384   R_unistep (no_states M) (graph_enum ?? (ntrans M)) (nhalt M) t1 t2 →
385   R_unistep_high M t1 t2.
386 #M #t1 #t2 #H whd whd in match (nconfig ?); #c #Ht1
387 lapply (initial_bar ? (nhalt M) (graph_enum ?? (ntrans M)) (nTM_nog ?)) #Htable
388 (* tup = current tuple *)
389 cut (∃t.t = 〈〈cstate … c,current ? (ctape … c)〉, 
390              ntrans M 〈cstate … c,current ? (ctape … c)〉〉) [% //] * #tup #Htup
391 (* tup is in the graph *)
392 cut (mem ? tup (graph_enum ?? (ntrans M)))
393   [@memb_to_mem >Htup @(graph_enum_complete … (ntrans M)) %] #Hingraph
394 (* tupe target = 〈qout,cout,m〉 *)
395 lapply (decomp_target ? (ntrans M 〈cstate … c,current ? (ctape … c)〉))
396 * #qout * #cout * #m #Htg >Htg in Htup; #Htup
397 (* new config *)
398 cut (step FinBool M c = mk_config ?? qout (tape_move ? (tape_write ? (ctape … c) cout) m))
399   [>(config_expand … c) whd in ⊢ (??%?); (* >Htg ?? why not?? *)
400    cut (trans ? M 〈cstate  … c, current ? (ctape … c)〉 = 〈qout,cout,m〉) [<Htg %] #Heq1 
401    >Heq1 %] #Hstep
402 (* new state *)
403 cut (cstate ?? (step FinBool M c) = qout) [>Hstep %] #Hnew_state
404 (* new tape *)
405 cut (ctape ?? (step FinBool M c) = tape_move ? (tape_write ? (ctape … c) cout) m)
406   [>Hstep %] #Hnew_tape
407 lapply(H (bits_of_state ? (nhalt M) (cstate ?? c)) 
408          (low_char (current ? (ctape ?? c)))
409          (tail ? (table_TM ? (graph_enum ?? (ntrans M)) (nhalt M)))
410          ??????)
411 [<Htable
412  lapply(list_to_table … (nhalt M) …Hingraph) * #ll * #lr #Htable1 %{ll} 
413  %{(((bits_of_state ? (nhalt M) qout)@[low_char cout;low_mv m])@lr)} 
414  >Htable1 @eq_f <associative_append @eq_f2 // >Htup
415  whd in ⊢ (??%?); @eq_f >associative_append %
416 |>Ht1 >obj_low_tapes >map_list_of_tape elim (list_of_tape ??) 
417   [#b @False_ind | #b #tl #Hind #a * [#Ha >Ha //| @Hind]]
418 |@sym_eq @Htable
419 |>Ht1 %
420 |%{(bits_of_state ? (nhalt M) (cstate ?? c))} %{(low_char (current ? (ctape ?? c)))}
421  % [% [% [// | cases (current ??) normalize [|#b] % #Hd destruct (Hd)]
422       |>length_map whd in match (length ??); @eq_f //]
423    |//]
424 |>Ht1 >cfg_low_tapes //] -H #H 
425 lapply(H (bits_of_state … (nhalt M) qout) (low_char … cout) 
426          (low_mv … m) tup ? Hingraph)
427   [>Htup whd in ⊢ (??%?); @eq_f >associative_append %] -H
428 #Ht2 @(eq_vec ? 3 ?? (niltape ?) ?) >Ht2 #i #Hi 
429 cases (le_to_or_lt_eq … (le_S_S_to_le … Hi)) -Hi #Hi
430   [cases (le_to_or_lt_eq … (le_S_S_to_le … Hi)) -Hi #Hi
431     [cases (le_to_or_lt_eq … (le_S_S_to_le … Hi)) -Hi #Hi
432       [@False_ind /2/
433       |>Hi >obj_low_tapes >nth_change_vec //
434        >Ht1 >obj_low_tapes >Hstep @map_action 
435       ]
436     |>Hi >cfg_low_tapes >nth_change_vec_neq 
437       [|% whd in ⊢ (??%?→?);  #H destruct (H)]
438      >nth_change_vec // >Hnew_state @eq_f @eq_f >Hnew_tape 
439      @eq_f2 [|2:%] >Ht1 >obj_low_tapes >map_move_mono >low_char_current %
440     ]
441   |(* program tapes do not change *)
442    >Hi >prg_low_tapes 
443    >nth_change_vec_neq [|% whd in ⊢ (??%?→?);  #H destruct (H)]
444    >nth_change_vec_neq [|% whd in ⊢ (??%?→?);  #H destruct (H)]
445    >Ht1 >prg_low_tapes //
446   ]
447 qed.