Require Import FunInd.

From Undecidability Require Import TM.Util.Prelim.
From Undecidability Require Import TM.Basic.Basic.
From Undecidability Require Import TM.Combinators.Combinators.
From Undecidability.TM.Compound Require Import TMTac Multi MoveToSymbol.

Require Recdef.



Set Default Proof Using "Type".
Section Compare.
  Import Recdef.

  Variable sig : finType.
  Variable stop : sig bool.
  Definition Compare_Step : pTM sig (option bool) 2 :=
    Switch
      ( ( c1 c2
                    match , with
                    | Some , Some
                      if (stop ) && (stop )
                      then Some true
                      else if (stop ) || (stop )
                           then Some false
                           else if Dec ( = )
                                then None
                                else Some false
                    | _, _ Some false
                    end))
      ( x : option bool match x with
                        | Some b Return Nop (Some b)
                        | None Return (MovePar Rmove Rmove) None
                        end).

  Definition Compare_Step_Rel : pRel sig (option bool) 2 :=
     tin '(yout, tout)
      match current tin[@], current tin[@] with
      | Some , Some
        if (stop ) && (stop )
        then yout = Some true tout = tin
        else if (stop ) || (stop )
             then yout = Some false tout = tin
             else if Dec ( = )
                  then yout = None tout[@] = tape_move_right tin[@] tout[@] = tape_move_right tin[@]
                  else yout = Some false tout = tin
      | _, _ yout = Some false tout = tin
      end.

  Lemma Compare_Step_Sem : Compare_Step c(5) Compare_Step_Rel.
  Proof.
    eapply RealiseIn_monotone.
    { unfold Compare_Step. TM_Correct. }
    { Unshelve. 4,7: reflexivity. all: . }
    { intros tin (yout, tout) H. TMCrush; TMSolve 1. }
  Qed.


  Definition Compare := While Compare_Step.

  Definition Compare_fun_measure (t : tape sig * tape sig) : := length (tape_local (fst t)).

  Function Compare_fun (t : tape sig * tape sig) {measure Compare_fun_measure t} : bool * (tape sig * tape sig) :=
    match (current (fst t)), (current (snd t)) with
    | Some , Some
        if (stop ) && (stop )
        then (true, t)
        else if (stop ) || (stop )
             then (false, t)
             else if Dec ( = )
                  then Compare_fun (tape_move_right (fst t), tape_move_right (snd t))
                  else (false, t)
    | _, _ (false, t)
    end.
  Proof.
    intros (&). intros . cbn in *.
    destruct ; cbn in *; inv . destruct ; cbn in *; inv .
    unfold Compare_fun_measure. cbn. simpl_tape. intros. .
  Qed.


  Definition Compare_Rel : pRel sig bool 2 :=
     tin '(yout, tout) (yout, (tout[@], tout[@])) = Compare_fun (tin[@], tin[@]).

  Lemma Compare_Realise : Compare Compare_Rel.
  Proof.
    eapply Realise_monotone.
    { unfold Compare. TM_Correct. eapply RealiseIn_Realise. apply Compare_Step_Sem. }
    { apply WhileInduction; intros; cbn in *.
      - revert yout HLastStep. TMCrush; intros; rewrite Compare_fun_equation; cbn; TMSolve 1.
        all:try rewrite E in *; try rewrite in *;try rewrite in *;try rewrite in *.
        all: TMCrush; TMSolve 1.
      - revert yout HLastStep. TMCrush; intros. all:TMSimp. all:rewrite HLastStep.
        all:symmetry. all:rewrite Compare_fun_equation. all:cbn. all:rewrite E, , , . all:decide (=) as [ | Tamtam]; [ | now contradiction Tamtam] . all:auto.
    }
  Qed.


  Local Arguments plus : simpl never.

  Function Compare_steps (t : tape sig * tape sig) { measure Compare_fun_measure} : :=
    match (current (fst t)), (current (snd t)) with
    | Some , Some
        if (stop ) && (stop )
        then 5
        else if (stop ) || (stop )
             then 5
             else if Dec ( = )
                  then 6 + Compare_steps (tape_move_right (fst t), tape_move_right (snd t))
                  else 5
    | _, _ 5
    end.
  Proof.
    intros (&). intros . cbn in *.
    destruct ; cbn in *; inv . destruct ; cbn in *; inv .
    unfold Compare_fun_measure. cbn. simpl_tape. intros. .
  Qed.


  Definition Compare_T : tRel sig 2 :=
     tin k Compare_steps (tin[@], tin[@]) k.

  Lemma Compare_steps_ge t : 5 Compare_steps t.
  Proof. functional induction Compare_steps t; auto. . Qed.

  Lemma Compare_TerminatesIn : Compare Compare_T.
  Proof.
    eapply TerminatesIn_monotone.
    { unfold Compare. TM_Correct.
      - eapply RealiseIn_Realise. apply Compare_Step_Sem.
      - eapply RealiseIn_TerminatesIn. apply Compare_Step_Sem. }
    { apply WhileCoInduction; intros. exists 5. split. reflexivity. intros [ yout | ].
      - intros. hnf in HT. TMCrush. all: rewrite HT. all: apply Compare_steps_ge.
      - intros. hnf in HT. exists (Compare_steps (tape_move tin[@] Rmove, tape_move tin[@] Rmove)).
        TMCrush.
        split.
        + hnf. TMSimp. auto.
        + rewrite Compare_steps_equation in HT. cbn in HT. rewrite E, , , in HT. rewrite in *. .
    }
  Qed.


End Compare.

Section CompareLists.

  Variable X : eqType.

  Definition list_comperasion (xs ys : list X) : Prop :=
    xs = ys
    ( a b l1 l2 l3, a b xs = a :: ys = b :: )
    ( a l1 l2, xs = a :: ys = )
    ( a l1 l2, xs = ys = a :: ).

  Definition list_comperasion_cons xs ys x :
    list_comperasion xs ys
    list_comperasion (x :: xs) (x :: ys).
  Proof.
    destruct 1 as [ | [ (a&b&&&&&&) | [ (a&&&&) | (a&&&&) ]]].
    - left. reflexivity.
    - subst. right; left. exists a, b, (x::), , . auto.
    - subst. right. right. left. do 3 eexists. split. 2: reflexivity. cbn. eauto.
    - subst. right. right. right. do 3 eexists. split. 1: reflexivity. cbn. eauto.
  Qed.


  Lemma compare_lists (xs ys : list X) :
    list_comperasion xs ys.
  Proof.
    revert ys. induction xs as [ | x xs IH]; intros; cbn in *.
    - destruct ys as [ | y ys].
      + left. reflexivity.
      + right. right. right. do 3 eexists. split. reflexivity. cbn. reflexivity.
    - destruct ys as [ | y ys].
      + hnf. right. right. left. do 3 eexists. split. 2: reflexivity. cbn. reflexivity.
      + decide (x = y) as [ | HDec].
        * now apply list_comperasion_cons.
        * hnf. right. left. exists x, y, nil. cbn. do 2 eexists. eauto.
  Qed.


End CompareLists.

Local Arguments plus : simpl never.
Local Arguments mult : simpl never.

Section Compare_fun_lemmas.

  Variable (X : finType) (stop : X bool).

  Lemma Compare_correct_eq (str : list X) (s1 s2 : X) rs1 rs2 t :
    ( x, In x str stop x = false)
    stop = true
    stop = true
    tape_local (fst t) = str ::
    tape_local (snd t) = str ::
    Compare_fun stop t =
    (true, (midtape (rev str left (fst t)) , midtape (rev str left (snd t)) )).
  Proof.
    revert str . functional induction (Compare_fun stop t); intros str HStr ; destruct t as [ ]; cbn in *;
                                try rewrite in *; try rewrite in *; cbn in *; auto.
    - destruct str as [ | s str']; cbn in *.
      + apply midtape_tape_local_cons in as . apply midtape_tape_local_cons in as . cbn. reflexivity.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in .
        rewrite in *. cbn in *. inv e. rewrite in *. cbn in *. inv .
        specialize (HStr ltac:(auto)). rewrite HStr in . cbn in *. congruence.
    - exfalso. destruct str as [ | s str']; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . rewrite , in . cbn in *. congruence.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv .
        specialize (HStr ltac:(auto)). rewrite HStr in *. cbn in *. congruence.
    - destruct str as [ | s str']; cbn in *.
      + exfalso. apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . rewrite in . cbn in *. congruence.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv .
        apply orb_false_iff in as (&_).
        simpl_tape in IHp. specialize IHp with (4 := eq_refl) (5 := eq_refl) (2 := ) (3 := ). spec_assert IHp by auto.
        simpl_list; cbn; auto.
    - exfalso. destruct str as [ | s str']; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . rewrite , in . cbn in *. congruence.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv .
        specialize (HStr ltac:(auto)). rewrite HStr in *. cbn in *. congruence.
    - exfalso. destruct str as [ | s str']; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. auto.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. auto.
  Qed.


  Lemma Compare_correct_eq_midtape (str : list X) (s1 s2 : X) ls1 rs1 ls2 m rs2 :
    ( x, In x str stop x = false)
    stop m = false
    stop = true
    stop = true
    Compare_fun stop (midtape m (str :: ), midtape m (str :: )) =
    (true, (midtape (rev str m :: ) , midtape (rev str m :: ) )).
  Proof.
    intros HStr Hm .
    rewrite Compare_fun_equation; cbn. erewrite Compare_correct_eq with (str := str) ( := ) ( := ) ( := ) ( := ); eauto.
    all: cbn; simpl_tape; auto.
    rewrite Hm. cbn. decide (m=m); [ | tauto]. now simpl_tape.
  Qed.


  Lemma Compare_correct_neq (str1 str2 str3 : list X) (x1 x2 : X) t :
    ( x, In x stop x = false)
    stop = false
    stop = false
    
    tape_local (fst t) = ::
    tape_local (snd t) = ::
    Compare_fun stop t =
    (false, (midtape (rev left (fst t)) , midtape (rev left (snd t)) )).
  Proof.
    revert . functional induction (Compare_fun stop t); intros ; intros ; destruct t as [ ]; cbn in *.
    - exfalso. destruct as [ | s ]; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . rewrite in . cbn in *. congruence.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. specialize ( s ltac:(eauto)). inv e; inv .
        rewrite in . cbn in *. congruence.
    - exfalso. destruct as [ | s ]; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . rewrite in . cbn in *. congruence.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. specialize ( s ltac:(eauto)).
        inv e; inv . rewrite in . cbn in *. congruence.
    - destruct as [ | s ]; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . tauto.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv .
        simpl_tape in IHp. specialize IHp with (5 := eq_refl) (6 := eq_refl) (2 := ) (3 := ) (4 := ). spec_assert IHp by auto.
        simpl_list; cbn; auto.
    - destruct as [ | s ]; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . rewrite in . cbn in *. congruence.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . now contradiction _x.
    - exfalso. destruct as [ | s ]; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. auto.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. auto.
  Qed.


  Lemma Compare_correct_neq_midtape (str1 str2 str3 : list X) (m x1 x2 : X) ls1 ls2 :
    ( x, In x stop x = false)
    stop = false
    stop = false
    stop m = false
    
    Compare_fun stop (midtape m ( :: ), midtape m ( :: )) =
    (false, (midtape (rev m :: ) , midtape (rev m :: ) )).
  Proof.
    intros Hm .
    rewrite Compare_fun_equation; cbn. rewrite Compare_correct_neq with ( := ) ( := ) ( := ) ( := ) ( := ).
    all: cbn; simpl_tape; auto.
    rewrite Hm. cbn. decide (m=m); [ | tauto]. now simpl_tape.
  Qed.


  Definition swap (A B : Type) : A*BB*A := ltac:(intros [b a]; now constructor).

  Lemma Compare_correct_swap t :
    Compare_fun stop (swap t) = (fst (Compare_fun stop t), swap (snd (Compare_fun stop t))).
  Proof.
    functional induction (Compare_fun stop t); destruct t as [ ]; cbn in *.
    - rewrite Compare_fun_equation. cbn. rewrite e, .
      rewrite andb_comm in . now rewrite .
    - rewrite Compare_fun_equation. cbn. rewrite e, .
      rewrite andb_comm in . rewrite orb_comm in . now rewrite , .
    - rewrite Compare_fun_equation. cbn. rewrite e, .
      rewrite , . decide (=) as [ ? | H]; [ | now contradiction H]. auto.
    - rewrite Compare_fun_equation. cbn. rewrite e, .
      rewrite andb_comm in . rewrite orb_comm in . rewrite , .
      decide (=) as [ | H]; [ now contradiction _x | ]. auto.
    - rewrite Compare_fun_equation. cbn.
      destruct (current ); auto; destruct (current ); auto.
  Qed.


  Lemma Compare_correct_short (str1 str2 rs1 rs2 : list X) (x : X) (s1 s2 : X) t :
    ( x, In x stop x = false)
    stop x = false
    stop = true
    stop = true
    tape_local (fst t) = x :: ::
    tape_local (snd t) = ::
    Compare_fun stop t =
    (false, (midtape (rev left (fst t)) x ( :: ),
             midtape (rev left (snd t)) )).
  Proof.
    revert x . functional induction (Compare_fun stop t); intros x ; intros Hx ; destruct t as [ ]; cbn in *.
    - exfalso. destruct as [ | s ]; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . rewrite Hx in . cbn in . congruence.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv .
        specialize ( ltac:(auto)). rewrite in . cbn in . congruence.
    - destruct as [ | s ]; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. auto.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv .
        specialize ( ltac:(auto)). rewrite in . cbn in . congruence.
    - destruct as [ | s ]; cbn in *.
      + exfalso. apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv .
        rewrite in . cbn in . congruence.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv .
        simpl_tape in IHp. specialize IHp with (2 := Hx) (3 := ) (4 := ) (5 := eq_refl) (6 := eq_refl). spec_assert IHp by auto.
        simpl_list; cbn; auto.
    - exfalso. destruct as [ | s ]; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv . rewrite Hx in . cbn in . congruence.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. inv e; inv .
        specialize ( ltac:(auto)). rewrite in . cbn in . congruence.
    - exfalso. destruct as [ | s ]; cbn in *.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. auto.
      + apply midtape_tape_local_cons in . apply midtape_tape_local_cons in . rewrite , in *. cbn in *. auto.
  Qed.


  Lemma Compare_correct_short_midtape (str1 str2 : list X) (x s1 s2 : X) ls1 rs1 ls2 m rs2 :
    ( x, In x stop x = false)
    stop m = false
    stop x = false
    stop = true
    stop = true
    Compare_fun stop (midtape m ( x :: :: ),
                      midtape m ( :: )) =
    (false, (midtape (rev m :: ) x ( :: ),
             midtape (rev m :: ) )).
  Proof.
    intros Hm Hx .
    erewrite Compare_correct_short with ( := m :: ) ( := ) ( := ) ( := ); cbn; eauto.
    - now simpl_list; cbn.
    - intros ? [ | H]; auto.
  Qed.


  Lemma Compare_correct_long_midtape (str1 str2 : list X) (x s1 s2 : X) ls1 rs1 ls2 m rs2 :
    ( x, In x stop x = false)
    stop m = false
    stop x = false
    stop = true
    stop = true
    Compare_fun stop (midtape m ( :: ),
                      midtape m ( x :: :: )) =
    (false, (midtape (rev m :: ) ,
             midtape (rev m :: ) x ( :: ))).
  Proof.
    change ((midtape m ( :: ), midtape m ( x :: :: ))) with (swap (midtape m ( x :: :: ), midtape m ( :: ))).
    change (midtape (rev m :: ) , midtape (rev m :: ) x ( :: )) with (swap (midtape (rev m :: ) x ( :: ), midtape (rev m :: ) )).
    intros. rewrite Compare_correct_swap. cbn. rewrite Compare_correct_short_midtape; eauto.
  Qed.


  Lemma Compare_steps_correct (str1 str2 : list X) (s1 s2 : X) rs1 rs2 t :
    stop = true
    stop = true
    tape_local (fst t) = ::
    tape_local (snd t) = ::
    Compare_steps stop t 5 + 6 * max (length ) (length ).
  Proof.
    revert . functional induction (Compare_steps stop t); intros ; intros ; destruct t as [ ]; cbn in *.
    all: try .     destruct as [ | s ], as [ | s' ]; cbn in *;
      apply midtape_tape_local_cons in ; apply midtape_tape_local_cons in ; rewrite , in *; cbn in *;
        inv e; inv .
    - exfalso. rewrite in . cbn in . congruence.
    - exfalso. rewrite in . cbn in . congruence.
    - exfalso. rewrite in . cbn in . congruence.
    - simpl_tape in IHn. specialize IHn with (1 := ) (2 := ) (3 := eq_refl) (4 := eq_refl). .
  Qed.


  Lemma Compare_steps_correct_midtape (str1 str2 : list X) (s1 s2 : X) (m : X) ls1 ls2 rs1 rs2 :
    stop = true
    stop = true
    Compare_steps stop (midtape m ( :: ), midtape m ( :: )) 11 + 6 * max (length ) (length ).
  Proof.
    intros . rewrite Compare_steps_correct with ( := m :: ) ( := m :: ) ( := ) ( := ); cbn; eauto. .
  Qed.


  Lemma Compare_Move_steps_midtape1 (stop' : X bool) (str1 str2 : list X) (s1 s2 : X) (m : X) ls1 ls2 rs1 rs2 :
    ( x, In x stop x = false)
    ( x, In x stop x = false)
    stop m = false
    stop = true
    stop = true
    stop' m = true
    ( x, In x stop' x = false)
    ( x, In x stop' x = false)
    MoveToSymbol_L_steps stop' id (fst (snd (Compare_fun stop (midtape m ( :: ), midtape m ( :: )))))
    8 + 4 * length .
  Proof.
    intros.
    pose proof compare_lists as[ HC | [ (a&b&&&&&&) | [ (a&&&&) | (a&&&&) ]]]; subst.
    - rewrite Compare_correct_eq_midtape; cbn; auto. rewrite MoveToSymbol_L_steps_midtape; auto. simpl_list. .
    - simpl_list; cbn. rewrite Compare_correct_neq_midtape; cbn; auto. rewrite MoveToSymbol_L_steps_midtape; auto. simpl_list. .
    - simpl_list; cbn. rewrite Compare_correct_short_midtape; cbn; auto. rewrite MoveToSymbol_L_steps_midtape; auto. simpl_list. .
    - simpl_list; cbn. rewrite Compare_correct_long_midtape; cbn; auto. rewrite MoveToSymbol_L_steps_midtape; auto. simpl_list. .
  Qed.


  Lemma Compare_Move_steps_midtape2 (stop' : X bool) (str1 str2 : list X) (s1 s2 : X) (m : X) ls1 ls2 rs1 rs2 :
    ( x, In x stop x = false)
    ( x, In x stop x = false)
    stop m = false
    stop = true
    stop = true
    stop' m = true
    ( x, In x stop' x = false)
    ( x, In x stop' x = false)
    MoveToSymbol_L_steps stop' id (snd (snd (Compare_fun stop (midtape m ( :: ), midtape m ( :: )))))
    8 + 4 * length .
  Proof.
    intros.
    pose proof compare_lists as[ HC | [ (a&b&&&&&&) | [ (a&&&&) | (a&&&&) ]]]; subst.
    - rewrite Compare_correct_eq_midtape; cbn; auto. rewrite MoveToSymbol_L_steps_midtape; auto. simpl_list. .
    - simpl_list; cbn. rewrite Compare_correct_neq_midtape; cbn; auto. rewrite MoveToSymbol_L_steps_midtape; auto. simpl_list. .
    - simpl_list; cbn. rewrite Compare_correct_short_midtape; cbn; auto. rewrite MoveToSymbol_L_steps_midtape; auto. simpl_list. .
    - simpl_list; cbn. rewrite Compare_correct_long_midtape; cbn; auto. rewrite MoveToSymbol_L_steps_midtape; auto. simpl_list. .
  Qed.


End Compare_fun_lemmas.