Reducing the Reachability of Turing Configurations to String Rewriting


Require Import Prelim Single_TM String_rewriting Reductions.

Section Fix_TM.
  Variable sig : finType.
  Variable T : (sTM sig).
  Definition conf :Type := mconfig sig (states T).

  Instance eq_dec_states : eq_dec (states T).
  Proof. exact _. Defined.

  Inductive rsig' : Type := hash | dollar | sigma (s: sig).

  Instance eq_dec_rsig' : eq_dec rsig'.
  Proof.
    intros. hnf. decide equality. apply eq_dec_sig.
  Defined.

  Instance finType_rsig': finTypeC (EqType rsig').
  Proof.
    exists (hash::dollar::(List.map (fun s => sigma s) (elem sig))).
    intros x. destruct x; cbn. induction (elem sig); auto. induction (elem sig); auto.
    apply inductive_count. intros x y; now inversion 1. apply (@enum_ok sig (class sig) s).
  Defined.


  Inductive rsig : Type := state (q: states T) | symb (s: (FinType (EqType rsig'))).
  Definition sym : sig -> rsig := fun s => symb (sigma s).
  Notation "#" := (symb hash).
  Notation "$" := (symb dollar).

  Instance eq_dec_rsig : eq_dec rsig.
  Proof.
    intros. hnf. decide equality. apply eq_dec_states.
    apply eq_dec_rsig'.
  Defined.

  Lemma state_count_one q:
    count (map (fun s : states T => state s) (elem (states T))) (state q) = 1.
  Proof.
    apply inductive_count. intros x y; now inversion 1.
    apply (@enum_ok (states T) (class (states T)) q).
  Qed.

  Lemma symb_count_one s:
    count (map (fun s0 : FinType (EqType rsig') => symb s0)
               (elem (FinType (EqType rsig')))) (symb s) = 1.
  Proof.
    apply inductive_count. intros x y; now inversion 1.
    apply (@enum_ok (FinType (EqType rsig')) (class (FinType (EqType rsig'))) s).
  Qed.


  Instance finType_rsig: finTypeC (EqType rsig).
  Proof.
    exists ((List.map (fun s => state s) (elem (states T)))
         ++ (List.map (fun s => symb s) (elem (FinType (EqType rsig'))))).
    intros x. destruct x.
    - rewrite in_count_app. rewrite state_count_one.
      remember (elem (FinType (EqType (rsig')))) as B.
      now rewrite (@diff_constructors_count_zero (FinType (EqType rsig'))
                                                 (EqType rsig) (states T) B symb state).
    - rewrite in_count_app. rewrite symb_count_one. remember (elem (states T)) as B.
      now rewrite (@diff_constructors_count_zero (states T)).
  Defined.

  Definition rsig_finType : finType := (@FinType (EqType rsig) finType_rsig).

  Definition halting_states : list (states T) :=
    List.filter (fun s => halt s) (elem (states T)).

  Definition not_halting_states : list (states T) :=
    List.filter (fun s => negb (halt s)) (elem (states T)).

  Lemma not_halting (q: states T) :
    halt q = false <-> q el not_halting_states.
  Proof.
    split. unfold not_halting_states. rewrite filter_In.
    intros H. split. auto. now rewrite H. unfold not_halting_states.
    rewrite filter_In. intros [H1 H2]. now destruct (halt q).
  Qed.

  Lemma halting (q: states T) :
    halt q = true <-> q el halting_states.
  Proof.
    split. unfold halting_states. rewrite filter_In.
    intros H. split. auto. now rewrite H. unfold halting_states.
    rewrite filter_In. intros []. auto.
  Qed.

Encoding of Configurations

  Definition mk_srconf (c: conf): list rsig :=
    match (ctape c) with
    | niltape _ => [state (cstate c);#;$]
    | leftof s r => [state(cstate c); #]++ (List.map sym (s::r))++[$]
    | rightof s l => [#]++(List.map sym (List.rev (s::l)))++[state(cstate c);$]
    | midtape l s r => [#]++(List.map sym (List.rev l))++ [(state(cstate c))]
                                ++ (List.map sym (s::r))++[$]
    end.

  Lemma sym_inj : Injective sym.
  Proof.
    intros x y. now inversion 1.
  Qed.

  Lemma state_not_sym A B q e l:
    A++[state q] = B ++sym e::(List.map sym l) -> False.
  Proof.
    revert B e. induction l; intros B e H; cbn in *.
    - apply last_app_eq in H as [H HE]. inv HE.
    - apply (IHl (B++[sym e]) a). now rewrite <- app_assoc.
  Qed.

  Lemma midtape_state A B q1 q2 l r:
    A ++ (state q1)::B = List.map sym l++(state q2)::(List.map sym r)
            -> A = List.map sym l /\ B = (List.map sym r) /\ q1 = q2.
  Proof.
    revert r A B. induction l; intros r A B H; cbn in *.
    - destruct A. rewrite app_nil_l in H. inv H. now split. inv H. exfalso.
      assert ((state q1) el (A++(state q1)::B) -> False). intros H. rewrite H2 in H.
      apply in_map_iff in H as [x [? ?]]. inv H. apply H. auto.
    - destruct A. rewrite app_nil_l in H. inv H. inv H. destruct (IHl r A B H2).
      subst. now split.
  Qed.

  Lemma mk_srconf_inj (c1 c2: conf) :
    mk_srconf c1 = mk_srconf c2 <-> c1 = c2.
  Proof.
    split.
    - unfold mk_srconf. destruct (ctape c1) eqn: H,(ctape c2) eqn: H'; try inversion 1;
                         subst; destruct c1,c2; cbn in *; subst; try reflexivity.
      + apply app_inv_tail in H4. apply map_inj in H4. now subst. apply sym_inj.
      + change [state cstate;$] with ([state cstate]++[$]) in H2.
        change [state cstate0;$] with ([state cstate0]++[$]) in H2.
        rewrite !app_assoc in H2. apply app_inv_tail in H2.
        apply last_app_eq in H2 as [H3 H2]. repeat rewrite map_app in H3.
        apply last_app_eq in H3 as [H3 HE]. inv H2. inv HE. rewrite map_inj in H3.
        rewrite rev_eq in H3. now subst. apply sym_inj.
      + change [state cstate; $] with ([state cstate]++[$]) in H2.
        rewrite !app_assoc, !app_comm_cons in H2. rewrite app_assoc in H2.
        apply last_app_eq in H2 as [H2 _]. exfalso.
        change (state cstate0::sym e0::List.map sym l1)
                   with ([state cstate0]++sym e0::List.map sym l1) in H2.
        rewrite app_assoc in H2. apply (state_not_sym H2).
      + change [state cstate0; $] with ([state cstate0]++[$]) in H2.
        rewrite !app_assoc, !app_comm_cons in H2. rewrite app_assoc in H2.
        apply last_app_eq in H2 as [H2 _]. symmetry in H2.
        change (state cstate::sym e::List.map sym l0)
                          with ([state cstate]++sym e::List.map sym l0) in H2.
        rewrite app_assoc in H2. exfalso. apply (state_not_sym H2).
      + rewrite !app_comm_cons in H2. rewrite! app_assoc in H2. apply last_app_eq in H2 as [H2 _].
        assert (List.map sym (List.rev l) ++ state cstate :: List.map sym (e::l0) =
                List.map sym (List.rev l1) ++ state cstate0 :: List.map sym (e0::l2)) as H3 by auto.
        apply midtape_state in H3 as [H3 [H4 H5]]. inv H4. apply map_inj in H6.
        subst. apply map_inj in H3. rewrite rev_eq in H3. now subst. apply sym_inj. apply sym_inj.
    - now intros <-.
  Qed.


Definition of Rewrite Rules Simulating a Transition


   Definition get_rules_left (q1 q2: states T) (old new: option sig) : list (list rsig * list rsig):=
    match old,new with
    |None,None => List.map (fun c => ([sym c; state q1; $], [state q2; sym c; $])) (elem sig)
    |None,Some b => List.map (fun c => ([sym c; state q1; $], [state q2; sym c; sym b; $])) (elem sig)
    |Some a,None => List.map (fun c => ([sym c; state q1; sym a], [state q2; sym c; sym a])) (elem sig)
    |Some a,Some b => List.map (fun c => ([sym c; state q1; sym a], [state q2; sym c; sym b])) (elem sig)
    end.

   Definition get_rules_right (q1 q2: states T) : list (list rsig * list rsig) :=
     List.map (fun a => ([state q1; #; sym a],[#; state q2; sym a])) (elem sig).

   Definition get_rules (q1 q2: states T) (old new: option sig) (m: move) :
     list (list rsig * list rsig) :=
    match old,new,m with
    |None,None,L => [([state q1; #],[state q2; #])] ++ (get_rules_left q1 q2 None None)
    |None,None,N => [([state q1; #],[state q2; #]);([state q1; $],[state q2; $])]
    |None,None,R => [([state q1; #;$],[state q2; #;$]); ([state q1; $],[state q2; $])]
                     ++ (get_rules_right q1 q2)
    |None,Some b,L => [([state q1; #],[state q2; #; sym b])] ++ (get_rules_left q1 q2 None (Some b))
    |None,Some b,N => [([state q1; #],[#; state q2; sym b]); ([state q1; $],[state q2; sym b; $])]
    |None,Some b,R => [([state q1; #],[#; sym b; state q2]); ([state q1; $],[sym b; state q2; $])]
    |Some a,None,L => [([#;state q1; sym a],[state q2; #; sym a])]
                       ++ (get_rules_left q1 q2 (Some a) None)
    |Some a,None,N => [([state q1; sym a],[state q2; sym a])]
    |Some a,None,R => [([state q1; sym a],[sym a; state q2])]
    |Some a,Some b,L => [([#; state q1; sym a],[state q2; #; sym b])]
                         ++ (get_rules_left q1 q2 (Some a) (Some b))
    |Some a,Some b,N => [([state q1; sym a],[state q2; sym b])]
    |Some a,Some b,R => [([state q1; sym a],[sym b; state q2])]
    end.


   Definition TMrules : list (list rsig * list rsig) :=
     List.concat ((List.map (fun q1 => match trans (q1,None) with
                      |(q2,(o,m)) => get_rules q1 q2 None o m
                                   end) not_halting_states) ++
                 (List.map (fun (P: states T * sig) => let (q1,s) := P in match trans (q1,Some s) with
                                                    |(q2,(o,m)) => get_rules q1 q2 (Some s) o m
                                                    end)
                           (list_prod not_halting_states (elem sig)))).

Correctness Proof


   Lemma get_rules_el_TMrules (q1 q2: states T) (old new: option sig) (m: move) :
     halt q1 = false -> (trans (q1,old) = (q2,(new,m)))
     -> get_rules q1 q2 old new m <<= TMrules.
   Proof.
     intros HF HT. intros s HS. apply in_concat_iff. exists (get_rules q1 q2 old new m).
     split. assumption. apply in_app_iff. destruct old.
     - right. apply in_map_iff. exists (q1,e). rewrite HT. split. reflexivity.
       apply in_prod_iff. split. now apply not_halting. auto.
     - left. apply in_map_iff. exists q1. rewrite HT. split. auto. now apply not_halting.
   Qed.

   Lemma rewrite_step_conf (c1: conf) :
    (halt (cstate c1) = false) -> rew TMrules (mk_srconf c1) (mk_srconf (step c1)).
   Proof.
     intros H. unfold mk_srconf. destruct (ctape c1) eqn: CT; unfold step; rewrite CT; cbn.
     - destruct (trans (cstate c1, None)) as (q2,(new,mov)) eqn: TC;
         assert (Sub: get_rules (cstate c1) q2 None new mov <<= TMrules)
         by (now apply get_rules_el_TMrules). destruct new as [new| ]; destruct mov; cbn.
       + apply rewR with (x:=[]) (u:= [state (cstate c1);#]) (v:=[state q2;#;sym new]).
         firstorder.
       + apply rewR with (x:=[]) (u:= [state (cstate c1);#]) (v:= [#;sym new; state q2]).
         firstorder.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #]) (v:=[#; state q2; sym new]).
         firstorder.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #]) (v:=[state q2; #]).
         firstorder.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #; $])(v:=[state q2; #; $]).
         firstorder.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #]) (v:=[state q2; #]).
         firstorder.
     - destruct (trans (cstate c1, None)) as (q2,(new,mov)) eqn: TC;
         assert (Sub: get_rules (cstate c1) q2 None new mov <<= TMrules)
         by (now apply get_rules_el_TMrules). destruct new as [new| ]; destruct mov; cbn.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #]) (v:=[state q2; #; sym new]).
         firstorder.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #]) (v:=[#; sym new; state q2]).
         firstorder.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #]) (v:=[#; state q2; sym new]).
         firstorder.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #])(v:=[state q2; #]).
         firstorder.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #; sym e]) (v:=[#; state q2; sym e]).
         apply Sub. cbn. right. right. unfold get_rules_right. apply in_map_iff. exists e. now split.
       + apply rewR with (x:=[]) (u:= [state (cstate c1); #]) (v:=[state q2; #]).
         firstorder.
     - destruct (trans (cstate c1, None)) as (q2,(new,mov)) eqn: TC;
         assert (Sub: get_rules (cstate c1) q2 None new mov <<= TMrules)
         by (now apply get_rules_el_TMrules). destruct new as [new| ]; destruct mov; cbn.
       + rewrite map_app. rewrite <- app_assoc.
         apply rewR with (x:=#::List.map sym (List.rev l)) (u:= [sym e; state (cstate c1); $])
                       (v:=[state q2; sym e; sym new;$]).
         apply Sub. cbn. right. apply in_map_iff. exists e. now split.
       + rewrite !map_app. setoid_rewrite <- app_assoc at 2.
         apply rewR with (x:=#::List.map sym (List.rev l) ++[sym e]) (u:= [state (cstate c1); $])
                       (v:=[sym new; state q2;$]). firstorder.
       + apply rewR with (x:=#::List.map sym (List.rev l++[e])) (u:= [state (cstate c1); $])
                       (v:=[state q2; sym new; $]). firstorder.
       + rewrite map_app. rewrite <- app_assoc.
         apply rewR with (x:=#::List.map sym (List.rev l)) (u:= [sym e; state (cstate c1); $])
                       (v:=[state q2; sym e;$]).
         apply Sub. cbn. right. apply in_map_iff. exists e. now split.
       + apply rewR with (x:=#::List.map sym (List.rev l++[e])) (u:= [state (cstate c1); $])
                       (v:=[state q2; $]). firstorder.
       + apply rewR with (x:=#::List.map sym (List.rev l++[e])) (u:= [state (cstate c1); $])
                       (v:=[state q2; $]). firstorder.
     - destruct (trans (cstate c1, Some e)) as (q2,(new,mov)) eqn: TC;
         assert (Sub: get_rules (cstate c1) q2 (Some e) new mov <<= TMrules)
         by (now apply get_rules_el_TMrules). destruct new as [new| ]; destruct mov; cbn.
       + destruct l; cbn.
         * apply rewR with (x:=[]) (u:= [#; state (cstate c1) ; sym e]) (v:=[state q2; #; sym new]).
           firstorder.
         * rewrite map_app. rewrite <- app_assoc.
           apply rewR with (x:=#::List.map sym (List.rev l))
                           (u:= [sym e0; state (cstate c1) ; sym e])
                           (v:=[state q2; sym e0; sym new]).
           apply Sub. cbn. right. apply in_map_iff. exists e0. now split.
       + destruct l0; cbn.
         * rewrite map_app. rewrite <- app_assoc.
           apply rewR with (x:= # :: List.map sym (List.rev l))
                           (u:= [state (cstate c1) ; sym e]) (y:=[$])
                           (v:=[sym new; state q2]). firstorder.
         * rewrite map_app. rewrite <- app_assoc.
           apply rewR with (x:=#::List.map sym (List.rev l))
                           (u:= [state (cstate c1) ; sym e])
                           (v:=[sym new; state q2]). firstorder.
       + apply rewR with (x:=# :: List.map sym (List.rev l)) (u:= [state (cstate c1); sym e])
                         (v:=[state q2; sym new]). firstorder.
       + destruct l; cbn.
         * apply rewR with (x:=[])
                           (u:= [#;state (cstate c1) ; sym e])
                           (v:=[state q2; #; sym e]). firstorder.
         * rewrite map_app. rewrite <- app_assoc.
           apply rewR with (x:=#::List.map sym (List.rev l))
                           (u:= [sym e0; state (cstate c1) ; sym e])
                           (v:=[state q2; sym e0; sym e]).
           apply Sub. cbn. right. apply in_map_iff. exists e0. now split.
       + destruct l0; cbn.
         * rewrite map_app. rewrite <- app_assoc.
            apply rewR with (x:=# :: List.map sym (List.rev l))
                            (u:= [state (cstate c1) ; sym e])
                            (v:=[sym e; state q2]). firstorder.
         * rewrite map_app. rewrite <- app_assoc.
           apply rewR with (x:=#::List.map sym (List.rev l))
                           (u:= [state (cstate c1) ; sym e])
                           (v:=[sym e; state q2]). firstorder.
       + apply rewR with (x:=# :: List.map sym (List.rev l))
                         (u:= [state (cstate c1); sym e])
                       (v:=[state q2; sym e]). firstorder.
  Qed.

  Lemma state_eqlist A B C D q1 q2:
    A ++(state q1)::B = C++(state q2)::D
    -> (exists (E F: list rsig'), C = List.map symb E /\ D = List.map symb F)
    -> A = C /\ B = D /\ q1 = q2.
  Proof.
    revert C. induction A; intros C H HA; destruct C; try rewrite !app_nil_l in H.
    - inv H. now split.
    - inv H. destruct HA as [E [F [H1 H2]]]. destruct E; inv H1.
    - rewrite <- app_comm_cons in H. inv H. destruct HA as [E [F [H1 H2]]].
      exfalso. assert ((state q1) el (A++(state q1)::B) -> False). intros H.
      rewrite H2 in H. apply in_map_iff in H as [x [? ?]]. inv H. apply H. auto.
    - inv H. specialize (IHA C H2). destruct HA as [E [F [H3 H4]]]. destruct E,F.
      inv H3. inv H3. cbn in H3. inv H3. destruct IHA as [<- [<- <-]]. exists E, []. now split.
      now split. cbn in H3. inv H3. destruct IHA as [<- [<- <-]]. exists E, (r1::F). now split.
      now split.
  Qed.

  Fact map_symb_sigma A :
    List.map symb (List.map sigma A) = List.map sym A.
  Proof.
    induction A. auto. cbn. now rewrite <- IHA.
  Qed.

  (* Automation for rewrite_step_halt Lemma. ListInv mainly eliminates contradictory
     assumptions while state_inv also solves cases *)


  Ltac listInv :=
    cbn in *;
    match goal with
    | [H: sym _ = sym _ |- _ ] => inv H
    | [H: [] = _ ::_ |- _ ] => inv H
    | [H: _::_ = _::_ |- _ ] => inv H
    | [H: []++ _ = _ |- _ ] => rewrite app_nil_l in H
    | [H: _ ++[] = _ |- _ ] => rewrite app_nil_r in H
    | [H: _ = []++ _ |- _ ] => rewrite app_nil_l in H
    | [H: _ = _ ++[] |- _ ] => rewrite app_nil_r in H
    | [H: [] = List.map sym ?L |- _ ] => destruct L eqn: ?
    | [H: List.rev ?L = [] |- _] => apply rev_nil in H
    | [H: _ ++ _::_ = [] |- _ ] => symmetry in H; now apply app_cons_not_nil in H
    | [H: [] = List.map _ (List.rev (_) ++ ?e) |- _ ] =>
      apply map_app in H; now apply app_cons_not_nil in H
    | [H: _ ++ [#] = List.map sym (List.rev _ ++ ?e) |- _ ] =>
      rewrite map_app in H; let E:= fresh "E" in apply last_app_eq in H as [_ E]; inv E
    | [H: ?x ++ [_] = #::(List.map sym ?L) |- _ ] => destruct x eqn: ?
    | [H: _ ++ [#] = List.map sym (List.rev ?L) |- _ ] => destruct L eqn: ?
    | [H: _ ++ [sym _] = List.map sym (List.rev ?L) |- _ ] => destruct L eqn:?
    | [H: _ ++ [sym _] = List.map sym (_ ++ [_]) |- _ ] =>
      rewrite map_app in H; apply last_app_eq in H as [? ?]
    | [H: ?A ++ _::_ = _::_ |- _ ] => destruct A eqn: ?
    end; subst.
  Ltac rep_listInv := repeat listInv.

  Ltac confeq :=
    unfold step; unfold mk_srconf;
    match goal with
      | [ |- (_::_ = _::_) /\ _ ] => split
      | [ |- (_::_ = _::_)] => reflexivity
      | [H: ctape _ = _ |- (_ = _) /\ _ ] => rewrite H
      | [H: trans(_,_) = _ |- _ ] => rewrite H
      | [H: _ |- mk_mconfig _ _ = mk_mconfig _ _ /\ _ ] => split
      | [ |- mk_mconfig _ _ = mk_mconfig _ _ ] => reflexivity
      | [H: (?q,_) el list_prod not_halting_states _ |- halt ?q = false ] =>
        apply in_prod_iff in H as [? _]; now apply not_halting
      | [H: _ el not_halting_states |- halt _ = false] => now apply not_halting
        end; subst; cbn in *; try now rewrite !map_app, <- !app_assoc.
  Ltac rep_confeq := repeat confeq.

  Ltac state_inv :=
    unfold get_rules_right in *;
    match goal with
    |[H: ?x ++ ?z::(state ?q)::?y = ?a::(?A++(state _ )::_) |- _] =>
     cbn in H; change (x++z::state q::y) with (x++[z]++(state q)::y) in H; rewrite app_assoc in H;
     rewrite app_comm_cons in H; eapply state_eqlist in H as [? [? ?]]
|[H: ?x ++ state _ :: ?y = state _ ::_ |- _ = _ /\ _ ] =>
     apply state_eqlist with (A:= x) (B:= y) (C:= []) in H as [? [? ?]]
|[H: ?x ++ ?z::state ?q :: ?y = state _ ::_ |- _ = _ /\ _ ] =>
     change (x++z::state q::y) with (x++[z]++state q::y) in H; rewrite app_assoc in H;
     apply state_eqlist with (A:=x++[z]) (B:= y) (C:= []) in H as [? [? ?]]
|[H: ?x ++(state _ )::?y = ?a::(?A ++ (state _ )::_) |- _ ] =>
     cbn in H; rewrite app_comm_cons in H; eapply state_eqlist in H as [? [? ?]]
|[H: _::_ = _::_ |- _ ] => inv H
    |[H: (_,_) el List.map _ _ |- (_ = _) /\ _] => apply in_map_iff in H as [? [? ?]]
|[H: (_,_) = (_,_) |- _ ] => inv H
    |[H: _ |- exists E F, [] = _ /\ [#;$] = _ ] => exists [],[hash; dollar]; now split
    |[H: _ |- exists E F, [] = _ /\ #::sym ?e::List.map sym ?L++[$] = _ ] =>
     exists [],(hash::sigma e::List.map sigma L++[dollar]); split; auto; cbn;
     rewrite map_app, map_symb_sigma; now cbn
    |[H: _ |- exists E F, #::(List.map sym ?A) = _ /\ [$] = _ ] =>
     exists (hash::(List.map sigma A)), [dollar]; split; auto; cbn;
     rewrite !map_app, map_symb_sigma; now cbn
    |[H: _ |- exists E F, #::(List.map sym ?A) = _ /\ sym ?e::(List.map sym ?L)++[$] = _ ] =>
     exists (hash::(List.map sigma A)), (sigma e::(List.map sigma L)++[dollar]);
     split; cbn; try rewrite map_app; now rewrite map_symb_sigma
    end.

  Ltac solve_inv := repeat (state_inv || confeq || listInv).

  Lemma rewrite_step_halt (c1: conf) y:
    rew TMrules (mk_srconf c1) y -> (y = (mk_srconf (step c1)) /\ (halt (cstate c1) = false)).
  Proof.
    intros H. remember (mk_srconf c1) as a. inv H.
    apply in_concat_iff in H0 as [L [EL HL]]. unfold mk_srconf in H2.
    destruct (ctape c1) eqn: CT1; cbn in *; apply in_app_iff in HL as [HL|HL];
      try apply in_map_iff in HL as [z [HZ ZF]]; try (destruct z as (q1, old));
        try (destruct (trans(z,None)) as (qz,(o,m)) eqn: TZ +
            destruct (trans (q1, Some old)) as (q2, (o, m)) eqn: TZ);
        destruct o as [new| ]; destruct m; cbn in HZ; subst; destruct EL;
          try apply in_sing in H; try inv H; solve_inv; destruct l0; cbn; rep_confeq.
  Qed.

  Theorem reach_rewrite (c1 c2:conf):
    reach c1 c2 <-> rewt TMrules (mk_srconf c1) (mk_srconf c2).
  Proof.
    split.
    - induction 1. constructor. apply rewtRule with (y:=(mk_srconf (step c))).
      + now apply rewrite_step_conf.
      + assumption.
    - remember (mk_srconf c1) as y. remember (mk_srconf c2) as b.
       intros H. revert Heqy. revert c1. induction H; intros c1 Heqy; subst.
       + apply mk_srconf_inj in Heqy. subst. constructor.
       + apply rewrite_step_halt in H as [H1 H]. subst.
         apply reachS. apply IHrewt; auto. assumption.
  Qed.

  Definition reduction_reach_rewrite (p: conf * conf) :=
      let (c1,c2) := p in (TMrules, mk_srconf c1, mk_srconf c2).

Reducing the Halting Problem to String Rewriting

Definition of Rewrite Rules Deleting Symbols

    Section abstract_epsilon.
    Variable gam: finType.
    Variable fin: list gam.

    Definition get_rule_l (f: gam) (r: gam) := ([r;f],[f]).
    Definition get_rule_r (f: gam) (r: gam) := ([f;r],[f]).
    Definition get_rule_fin (f: gam) : rule gam := ([f],[]).

    Definition del_rules_l : srs gam:=
      List.map (fun (P: (gam * gam)) => let (f, s) := P
                                     in get_rule_l f s) (list_prod fin (elem gam)).

    Definition del_rules_r : srs gam :=
      List.map (fun (P: (gam * gam)) => let (f, s) := P
                                     in get_rule_r f s) (list_prod fin (elem gam)).

    Definition del_rules_fin : srs gam := List.map get_rule_fin fin.
    Definition Drules := del_rules_r ++ del_rules_l ++ del_rules_fin.

    Lemma del_rule_r_el q r: q el fin -> get_rule_r q r el Drules.
    Proof.
      intros HT. apply in_app_iff. left. apply in_map_iff.
      exists (q,r). split. auto. apply in_prod_iff. auto.
    Qed.

    Lemma del_rule_l_el q r: q el fin -> get_rule_l q r el Drules.
    Proof.
      intros HT. apply in_app_iff. right. apply in_app_iff. left.
      apply in_map_iff. exists (q,r). split. auto. apply in_prod_iff. auto.
    Qed.

    Lemma del_rule_fin_el q: q el fin -> get_rule_fin q el Drules.
    Proof.
      intros HT. apply in_app_iff. right. apply in_app_iff. right.
      apply in_map_iff. exists q. now split.
    Qed.

    Lemma delete_list_right (A B: list gam) q:
      q el fin -> rewt Drules (A++q::B) (A++[q]).
    Proof.
      intros Hq. induction B.
      - constructor.
      - apply rewtRule with (y:= (A++q::B)).
        + eapply rewR with (x:=A) (u:= [q;a]) (v:=[q]). apply in_app_iff.
          left. apply in_map_iff. exists (q,a). split. auto. apply in_prod_iff. now split.
        + assumption.
    Qed.

    Lemma delete_list_left (A B: list gam) q:
      q el fin -> rewt Drules (A++q::B) (q::B).
    Proof.
      intros Hq. pattern A. apply (@size_induction (list gam) (@length gam)).
      intros C IH. replace C with (rev (rev C)) by (apply rev_involutive).
      remember (rev C) as D. destruct D; cbn. constructor.
      rewrite <- app_assoc. change ((rev D)++[e]++q::B) with (rev D++([e;q])++B).
      apply rewtRule with (y:= (rev D++q::B)).
      apply rewR with (x:=rev D) (u:= [e;q]) (v:=[q]). apply in_app_iff. right.
      apply in_app_iff. left. apply in_map_iff. exists (q,e). split. auto. apply in_prod_iff.
      now split. apply IH. destruct C. inv HeqD. rewrite rev_length.
      setoid_rewrite <- rev_length at 2. rewrite <- HeqD. cbn. omega.
    Qed.

    Lemma delete_fin q:
      q el fin -> rewt Drules [q] [].
    Proof.
      intros HF. apply rewtRule with (y:=[]).
        + eapply rewR with (x:=[]) (y:=[]) (u:=[q]) (v:=[]). now apply del_rule_fin_el.
        + constructor.
    Qed.

    Theorem fin_rewrite_nil (A: list gam) q:
      q el fin -> q el A -> rewt Drules A [].
    Proof.
      intros QF QA. apply in_split in QA as [a1 [a2 HA]].
      destruct a1, a2; try rewrite app_nil_l in HA; subst.
      - now apply delete_fin.
      - apply rewtTrans with (y:=[q]). now apply delete_list_right with (A:=[]).
        now apply delete_fin.
      - apply rewtTrans with (y:=[q]). now apply delete_list_left.
        now apply delete_fin.
      - apply rewtTrans with (y:=q::e0::a2).
        + now apply delete_list_left.
        + apply rewtTrans with (y:=[q]).
          * now apply delete_list_right with (A:=[]).
          * now apply delete_fin.
    Qed.

    Lemma rewrite_drules (A B: list gam) :
      rew Drules A B -> exists q, q el fin /\ q el A.
    Proof.
      inversion 1. apply in_app_iff in H0 as [B1|[B2|B3]%in_app_iff].
      - unfold del_rules_r in B1. apply in_map_iff in B1 as [[q s] [B1 B2]].
        inv B1. apply in_prod_iff in B2 as [B4 B5]. exists q. split; auto.
      - unfold del_rules_l in B2. apply in_map_iff in B2 as [[q s] [B1 B2]].
        inv B1. apply in_prod_iff in B2 as [B2 B3]. exists q. split; auto.
        apply in_app_iff. right. auto.
      - unfold del_rules_fin in B3. apply in_map_iff in B3 as [q [B5 B4]].
        inv B5. exists q. split; auto.
    Qed.

    End abstract_epsilon.

Correctness Proof

  Definition delRules := (Drules (List.map (fun s => state s) halting_states)).

  Theorem reach_rewrite_nil (c: conf):
     halt (cstate c) = true -> rewt delRules (mk_srconf c) [].
   Proof.
     intros H. apply fin_rewrite_nil with (q:= (state (cstate c))).
     apply in_map_iff. exists (cstate c). split. auto. now apply halting.
     unfold mk_srconf. destruct (ctape c); try (now left); apply in_app_iff.
     - right. apply in_app_iff. right. now left.
     - right. apply in_app_iff. right. apply in_app_iff. left. now left.
   Qed.

  Lemma mk_srconf_not_nil (con: conf):
    (mk_srconf con) <> [].
  Proof.
    unfold mk_srconf. destruct (ctape con); inversion 1.
  Qed.

  Lemma rew_delRules_halt c A:
    rew delRules (mk_srconf c) A -> halt (cstate c) = true.
   Proof.
     intros H. apply rewrite_drules in H as [q [H1 H2]]. unfold mk_srconf in H2.
     apply in_map_iff in H1 as [a [H4 H3]]. subst. destruct (ctape c).
     - inv H2. inv H. now apply halting. repeat (inv H; inv H0).
     - inv H2. inv H. now apply halting. repeat inv H; inv H0. inv H.
       apply in_app_iff in H as [H|H]. apply in_map_iff in H as [x [M N]]. inv M.
       apply in_sing in H. inv H.
     - repeat (apply in_app_iff in H2 as [H2|H2]).
       + apply in_sing in H2. inv H2.
       + apply in_map_iff in H2 as [x [M _]]. inv M.
       + inv H2. inv H. now apply halting. apply in_sing in H. inv H.
     - repeat (apply in_app_iff in H2 as [H2|H2]).
       + apply in_sing in H2. inv H2.
       + apply in_map_iff in H2 as [x [M _]]. inv M.
       + apply in_sing in H2. inv H2. now apply halting.
       + apply in_map_iff in H2 as [x [M _]]. inv M.
       + apply in_sing in H2. inv H2.
   Qed.

  Theorem rewrite_nil (c:conf):
    rewt (TMrules++delRules) (mk_srconf c) [] -> exists c1, reach c c1 /\ (halt (cstate c1) = true).
  Proof.
    remember (mk_srconf c) as y. remember [] as b. intros H. revert Heqy.
    revert c. induction H; intros c Heqc; subst.
    - exfalso. symmetry in Heqc. now apply mk_srconf_not_nil in Heqc.
    - remember (mk_srconf c) as a. assert (H' := H). inv H. apply in_app_iff in H1 as [H1|H1].
      + assert (rew TMrules (mk_srconf c) (x++v++y0)) as HR.
        { rewrite <- H3. now apply rewR with (x:=x) (u:=u). }
        apply rewrite_step_halt in HR as [HR1 HR2].
        destruct (IHrewt (eq_refl) (step c) HR1) as [c1 [RC HC]].
        exists c1. split. apply reachS; assumption. assumption.
      + assert (rew delRules (x++u++y0) (x++v++y0)) as HD.
        { now apply rewR with (x:=x) (u:=u) (v:=v). }
        rewrite H3 in HD. apply rew_delRules_halt in HD. exists c. split. constructor. assumption.
  Qed.

  Definition tm_srs_reduction (c: conf) : ((srs rsig * (list rsig)) * (list rsig)):=
    (TMrules ++ delRules, mk_srconf c, []).

  Theorem halt_iff_rewriting (c: conf) :
    (exists f :conf , halt (cstate f) = true /\ reach c f) <->
    rewt (TMrules ++ delRules) (mk_srconf c) [].
  Proof.
    split.
    - intros [fin [H1 H2]]. apply rewtTrans with (y:= mk_srconf fin).
      + assert (rewt TMrules (mk_srconf c) (mk_srconf fin)).
        apply (reach_rewrite c fin). assumption.
        apply (@subset_rewriting rsig TMrules). auto. assumption.
      + apply (@subset_rewriting rsig delRules). auto. now apply reach_rewrite_nil.
    - intros HR. apply rewrite_nil in HR as [c2 [H1 H2]]. exists c2. now split.
  Qed.

End Fix_TM.

Theorem reduction_reach_sr : red Reach SR.
Proof. unfold red. exists (fun S
                      => existT (fun (sig:finType) => (prod (prod (srs sig) (list sig)) (list sig)))
                               (rsig_finType (projT1 (projT2 S)))
                               (reduction_reach_rewrite (projT2 (projT2 S)))).
       intros [sig [M [c1 c2]]]. unfold Reach, SR. cbn. apply reach_rewrite.
Qed.

Theorem reduction_halt_sr : red HaltD SR.
Proof.
  unfold red. exists (fun (S: {sig : finType & sTM sig & tape sig})
                 => existT (fun (sig:finType) => (prod (prod (srs sig) (list sig)) (list sig)))
                          (rsig_finType (projT2 (sigT_of_sigT2 S)))
                          (tm_srs_reduction (initc (projT2 (sigT_of_sigT2 S)) (projT3 S)))).
  intros [sig [M con]]. unfold HaltD, SR. cbn. apply halt_iff_rewriting.
Qed.