Library DirectLinearizer

Require Export Omega Coq.Setoids.Setoid List Util AutoIndTac Base CFP Linearity TailRecursion Congruence.

Set Implicit Arguments.
Unset Printing Records.

Require Import Autosubst.

Traces of tail-recursive programs under substitution

Construction of traces of tail-recursive programs under substitution


Fact tailrec_subst_trace_compose1 n s xi1 sigma f
  : TC s xi1
    → ( i, i nsigma i = (ids (f i)))
    → boundT n xi1
    → TC s.[sigma] (ren_trace f xi1).
Proof.
  intros. general induction H; eauto using TC.
  - simpl. inv H1.
    rewrite H0; try omega.
    constructor.
  - simpl. inv H1.
    rewrite H0; try omega.
    constructor.
  - asimpl. rewrite ren_concat_distribute.
    decide (partial xi1).
    + rewrite concat_partial_absorb_right; eauto using ren_partial_preserve.
      rewrite <- concat_partial_absorb_right with (xi2 := P); eauto using ren_partial_preserve.
      constructor; eauto using TC.
      apply IHTC1 with (n:= n); eauto. apply boundT_concat_decompose_left with (xi2:= xi2). eauto.
    + constructor; eauto.
      × apply IHTC1 with (n:= n); eauto.
        apply boundT_concat_decompose_left with (xi2:= xi2). eauto.
      × apply IHTC2 with (n:= n); eauto.
        apply not_partial_total in n0.
        apply boundT_concat_decompose_right with (xi1:= xi1); eauto.
  - asimpl. constructor. rewrite up_change.
    rewrite <- subst_Fix_distribute.
    apply IHTC with (n:= n); eauto.
Qed.

Fact tailrec_subst_trace_compose2 s xi1 f sigma x n xi2
  : TC s xi1
    → ( i, i nsigma i = (ids (f i)))
    → x < n
    → terminal x xi1
    → boundT n (butLast xi1)
    → TC (sigma x) xi2
    → TC s.[sigma] (concat (butLast (ren_trace f xi1)) xi2).
Proof.
  intros. general induction H; eauto using TC.
  - inv H2.
  - simpl. inv H2; eauto.
    inv H8.
  - destruct (terminal_concat_decompose H3) as [[A B] | [A B] ].
    + destruct A as [A1 | [A2 | A3]].
      × rewrite concat_partial_absorb_right in H3; eauto.
        setoid_rewrite concat_partial_absorb_right at 2; eauto.
        assert (partial (butLast (ren_trace f xi1))).
        { rewrite ren_butLast_distribute. apply ren_partial_preserve.
          apply butLast_partial_preserve. eauto. }
        rewrite concat_partial_absorb_right; eauto.
        asimpl. rewrite <- concat_partial_absorb_right with (xi2:= P); eauto.
        constructor; eauto using TC.
        rewrite <- concat_partial_absorb_right with (xi2:= P); eauto.
        apply IHTC1 with (x:= x) (n:= n); eauto using TC.
        rewrite concat_partial_absorb_right in H4; eauto.
      × asimpl. rewrite A2 in H3. rewrite <- concat_T_iden_right in H3.
        rewrite A2. rewrite <- concat_T_iden_right.
        setoid_rewrite concat_T_iden_right at 1.
        constructor; eauto.
        { apply IHTC1 with (x:= x) (n:= n); eauto.
          rewrite A2 in H4. rewrite <- concat_T_iden_right in H4.
          eauto. }
        {rewrite A2 in H0. apply subst_trace_construct with (xi:= T); eauto using substT. }
      × asimpl. rewrite <- concat_partial_absorb_right with (xi2:= P).
        { constructor; eauto using TC.
          rewrite A3. rewrite ren_butLast_distribute.
          rewrite butLast_P_distribute. rewrite ren_concat_distribute.
          rewrite <- ren_butLast_distribute.
          rewrite concat_partial_absorb_right.
          - apply IHTC1 with (x:= x) (n:= n); eauto.
            + rewrite A3 in H4. rewrite butLast_P_distribute in H4.
              apply boundT_concat_decompose_left in H4. eauto.
            + simpl. eauto using TC.
          - simpl. apply concat_P_partial_right. }
        { rewrite concat_partial_absorb_right.
          - apply butLast_partial_preserve.
            apply ren_partial_preserve. rewrite A3.
            apply concat_P_partial_right.
          - apply butLast_partial_preserve.
            apply ren_partial_preserve. rewrite A3.
            apply concat_P_partial_right. }
    + simpl. rewrite ren_concat_distribute.
      rewrite butLast_concat_distribute.
      { rewrite concat_assoc. constructor.
        - apply tailrec_subst_trace_compose1 with (n:= n); eauto.
          rewrite butLast_concat_distribute in H4; eauto.
          + apply boundT_concat_decompose_left in H4. eauto.
          + apply terminal_composed with (x:= x). eauto.
        - apply IHTC2 with (x:= x) (n:= n); eauto.
          rewrite butLast_concat_distribute in H4; eauto.
          + apply boundT_concat_decompose_right in H4; eauto.
          + apply terminal_composed with (x:= x). eauto. }
      { apply ren_composed_preserve. apply terminal_composed with (x:= x). eauto. }
      { apply ren_total_preserve. eauto. }
  - asimpl. constructor. rewrite up_change. asimpl in IHTC.
    assert (s.[CFPFix s.[up sigma] .: sigma] = s.[CFPFix s/].[sigma]).
    { asimpl. eauto. }
    rewrite H5. apply IHTC with (x:= x) (n:= n); eauto.
Qed.

Deconstruction of traces of tail-recursive programs under substition


Fact tailrec_subst_trace_decompose n s sigma f xi
  : tailrec n s
    → TCsubst s sigma xi
    → ( i, i nsigma i = (ids (f i)))
    → ( xi', TC s xi' xi = ren_trace f xi' boundT n xi')
        ( xi1 xi2 x,
              TC s xi1
               TC (sigma x) xi2
               terminal x xi1
               x < n
               xi = concat (butLast (ren_trace f xi1)) xi2
               boundT n (butLast xi1)).
Proof.
  intros. general induction H0.
  - left. P. split; eauto using TC, boundT.
  - left. T. split; eauto using TC, boundT.
  - decide (x < n).
    + right. (V x T), xi, x.
      split; eauto using TC. split; eauto. split; eauto using terminal.
      split; eauto. split; eauto. constructor.
    + left. rewrite H1 in H; try omega.
      inv H.
      × P. split; eauto using TC. split; eauto using boundT.
      × (V x P). split; eauto using TC. split; eauto using boundT.
        constructor; eauto using boundT. omega.
      × (V x T). split; eauto using TC. split; eauto using boundT.
        constructor; eauto using boundT. omega.
  - inv H.
    destruct (IHTCsubst1 n f H5 H1) as [[xiC1 [A1 [B1 C1]]] | [xiA1 [xiB1 [x [C1 [D1 [E1 [F1 [G1 I1]]]]]]]]].
    + destruct (IHTCsubst2 n f H6 H1) as [[xiC2 [A2 [B2 C2]]] | [xiA2 [xiB2 [x2 [C2 [D2 [E2 [F2 [G2 I2]]]]]]]]].
      { left. (concat xiC1 xiC2). split; eauto using TC.
        split; eauto.
        - rewrite B1. rewrite B2.
          rewrite ren_concat_distribute. eauto.
        - apply boundT_concat_compose; eauto. }
      { decide (partial xiC1).
        - left. xiC1. split.
          + rewrite <- concat_partial_absorb_right with (xi2:= P); eauto.
            constructor; eauto using TC.
          + rewrite concat_partial_absorb_right; eauto.
            rewrite B1. apply ren_partial_preserve. eauto.
        - apply not_partial_total in n0.
          right.
           (concat xiC1 xiA2), xiB2, x2.
          split; eauto using TC. split; eauto.
          split; eauto using terminal.
          + apply terminal_concat_compose with (n:= n); eauto.
          + split; eauto.
            split.
            × rewrite G2. rewrite ren_concat_distribute.
              rewrite butLast_concat_distribute; eauto.
              { rewrite concat_assoc. rewrite <- B1. eauto. }
              { apply ren_composed_preserve. apply terminal_composed with (x:= x2). eauto. }
              { apply ren_total_preserve. eauto. }
            × rewrite butLast_concat_distribute; eauto using terminal_composed.
              apply boundT_concat_compose; eauto. }
    + apply bound_boundT with (xi:= xiA1) in H3; eauto.
      exfalso. eapply terminal_boundT_contradict with (n:= n) (x:= x) (xi:= xiA1); eauto.
  - inv H.
    destruct (IHTCsubst n f H5 H1) as [[xiC [A [B I]]] | [xiA [xiB [x [C [D [E [F [G I]]]]]]]]].
    + left. xiC. split; eauto using TC.
    + right. xiA, xiB, x. split; eauto using TC.
  - inv H.
    destruct (IHTCsubst n f H6 H1) as [[xiC [A [B I]]] | [xiA [xiB [x [C [D [E [F [G I]]]]]]]]].
    + left. xiC. split; eauto using TC.
    + right. xiA, xiB, x. split; eauto using TC.
  - destruct (IHTCsubst n f) as [[xiC [A [B I]]] | [xiA [xiB [x [C [D [E [F [G I]]]]]]]]]; eauto.
    + inv H. rewrite substPos_zero_extens.
      apply tailrec_subst_preserve; eauto. omega.
    + left. xiC. split; eauto using TC.
    + right. xiA, xiB, x. split; eauto using TC.
Qed.

Linearizer


Fixpoint linearize (n:nat) (s u: cfp) :=
  match s with
  | CFPEpsu
  | (CFPVar x) ⇒ if (decision (x < n)) then (CFPVar x) else (CFPSeq (CFPVar x) u)
  | (CFPSeq s t) ⇒ linearize n s (linearize n t u)
  | (CFPChoice s t) ⇒ CFPChoice (linearize n s u) (linearize n t u)
  | (CFPFix s) ⇒ CFPFix (linearize (S n) s u.[ren(+1)])
  end.

Correctness of the linearizer

Preservation of tail recursion


Lemma linearize_tailrec n s u
  : tailrec n s
    → tailrec n u
    → tailrec n (linearize n s u).
Proof.
  intros. general induction H; eauto using tailrec.
  - simpl. decide (m < n); eauto using tailrec.
    constructor; eauto using tailrec.
    constructor 3. omega.
  - simpl. constructor. apply IHtailrec. apply tailrec_ren_preserve with (n:= n); eauto; intros; simpl; omega.
Qed.

Establishment of linearity


Lemma linearize_lin n s u
  : tailrec n s
    → lin n u
    → lin n (linearize n s u).
Proof.
  intros. general induction H; eauto using lin.
  - simpl. decide (m < n); eauto using lin.
    constructor; eauto. omega.
  - simpl. constructor. apply IHtailrec.
    apply lin_ren_preserve with (n:= n); eauto.
    intros. simpl. omega.
Qed.

Trace construction of linearized programs


Lemma linearize_correct1 n x s u xi xi1 xi2
  : tailrec n s
    → (TC s xix < nterminal x xiTC (linearize n s u) xi)
        (TC s xiboundT n xipartial xiTC (linearize n s u) xi)
        (TC s xi1total xi1boundT n xi1TC u xi2TC (linearize n s u) (concat xi1 xi2)).
Proof.
  intros. general induction H; intros.
  - repeat split; simpl; intros.
    + inv H; inv H1.
    + inv H; eauto using TC. inv H1.
    + inv H.
      × rewrite concat_partial_absorb_right; eauto using TC, partial.
      × rewrite <- concat_T_iden_left. eauto.
  - repeat split; simpl; intros.
    + decide (m < n); eauto.
      assert (x m); try omega.
      inv H; eauto using TC; inv H1; try omega; inv H7.
    + decide (m < n); eauto. apply trace_partial_Seq_left; eauto.
    + decide (m < n); eauto. inv H; inv H0; inv H4.
      × inv H1. exfalso. omega.
      × constructor; eauto.
  - destruct (IHtailrec1 x u xi xi1 xi2) as [IH1s [IH2s IH3s]].
    destruct (IHtailrec2 x u xi xi1 xi2) as [IH1t [IH2t IH3t]].
    repeat split; simpl; intros; inv H1; eauto using TC.
  - repeat split; simpl; intros.
    + inv H2; eauto using TC.
      apply bound_boundT with (xi:= xi0) in H; eauto.
      destruct (terminal_concat_decompose H4) as [[[H5 | [H5 | H5]] H10] | [H6 H8]];
        [exfalso; apply terminal_boundT_contradict with (n:= n) (xi:= xi0) (x:= x); eauto..|].
      destruct (IHtailrec2 x u xi3 xi1 xi2) as [IH1t [IH2t IH3t]].
      specialize (IH1t H9 H3 H8).
      destruct (IHtailrec1 x (linearize n t u) xi1 xi0 xi3) as [IH1s [IH2s IH3s]].
      eauto.
    + inv H2; eauto using TC.
      decide (partial xi0).
      × rewrite concat_partial_absorb_right; eauto.
        rewrite concat_partial_absorb_right in H3; eauto.
        destruct (IHtailrec1 x (linearize n t u) xi0 xi0 xi3) as [IH1s [IH2s IH3s]].
        eauto.
      × apply not_partial_total in n0.
        assert (boundT n xi0); eauto using boundT_concat_decompose_left.
        apply boundT_concat_decompose_right in H3; eauto. destruct (IHtailrec1 x (linearize n t u) xi0 xi0 xi3) as [IH1s [IH2s IH3s]]. apply IH3s; eauto.
        destruct (IHtailrec2 x u xi3 xi1 xi2) as [IH1t [IH2t IH3t]].
        apply IH2t; eauto. apply concat_partial_compose with (xi1:= xi0); eauto.
    + inv H2; eauto using TC. rewrite concat_assoc.
      destruct (concat_total_decompose H3) as [A B].
      assert (boundT n xi0); eauto using boundT_concat_decompose_left.
      apply boundT_concat_decompose_right in H4; eauto.
      destruct (IHtailrec1 x (linearize n t u) xi xi0 (concat xi3 xi2)) as [IH1t [IH2t IH3t]]. apply IH3t; eauto.
      destruct (IHtailrec2 x u xi xi3 xi2) as [IH1s [IH2s IH3s]]. eauto.
  - repeat split; simpl; intros.
    + apply Fix_unfold_subsume in H0. destruct H0 as [m H0]. general induction m; simpl in H0.
      × apply Null_trace in H0. rewrite H0. eauto using TC.
      × apply TC_TCsubst in H0.
        destruct (@tailrec_subst_trace_decompose 1 s (unfold s m .: ids) shift xi) as [[xiA [A1 [A2 A3]]] | [xiA [xiB [y [B2 [B3 [B4 [B5 [B6 B7]]]]]]]]]; eauto using simulate_shift.
        { apply tailrec_step with (n:= S n); eauto. omega. }
        { destruct (IHtailrec (S x) u.[ren(+1)] xiA xi1 xi2) as [IH1 [IH2 IH3]].
          assert (TC (linearize (S n) s u.[ren(+1)]) xiA).
          { apply IH1; eauto; try omega. rewrite A2 in H2.
            apply terminal_ren_shift_reconstruct; eauto. }
          constructor. rewrite A2. apply tailrec_subst_trace_compose1 with (n:= 1); eauto using simulate_shift. }
        { destruct (IHtailrec 0 u.[ren(+1)] xiA xi1 xi2) as [IH1 [IH2 IH3]].
          assert (y =0). { destruct y; eauto. inv B5. inv H4. }
                         rewrite H3 in B4.
          assert (TC (linearize (S n) s u.[ren(+1)]) xiA).
          { rewrite B6 in H2.
            apply IH1; eauto; try omega. }
          constructor. rewrite B6.
          assert (TC (CFPFix (linearize (S n) s u.[ren (+1)])) xiB).
          { rewrite H3 in B3. asimpl in B3.
            apply IHm with (x:= x); eauto.
            rewrite B6 in H2. apply terminal_concat_decompose_right with (n:= n) in H2; eauto.
            rewrite ren_butLast_distribute. apply boundT_ren_shift_preserve.
            apply tailrec_trace_butLast_boundT.
            apply tailrec_tailrec_trace with (s:= s); eauto. }
          apply tailrec_subst_trace_compose2 with (x:= 0) (n:= S n); eauto using simulate_shift; try omega.
          apply tailrec_trace_butLast_boundT. apply tailrec_tailrec_trace with (s:= s); eauto. }
    + apply Fix_unfold_subsume in H0. destruct H0 as [m H0]. general induction m; simpl in H0.
      × apply Null_trace in H0. rewrite H0. eauto using TC.
      × apply TC_TCsubst in H0.
        destruct (@tailrec_subst_trace_decompose 1 s (unfold s m .: ids) shift xi) as [[xiA [A1 [A2 A3]]] | [xiA [xiB [y [B2 [B3 [B4 [B5 [B6 B7]]]]]]]]]; eauto using simulate_shift.
        { apply tailrec_step with (n:= S n); eauto. omega. }
        { constructor. destruct (IHtailrec (S x) u.[ren(+1)] xiA xi1 xi2)
            as [IH1 [IH2 IH3]].
          rewrite A2. apply tailrec_subst_trace_compose1 with (n:= 1); eauto using simulate_shift.
          apply IH2; eauto.
          - rewrite A2 in H1. apply boundT_ren_shift_reconstruct; eauto.
          - rewrite A2 in H2. apply ren_partial_origin with (f:= shift). eauto. }
        { decide (partial xiA).
          - rewrite concat_partial_absorb_right in B6; eauto using butLast_partial_preserve, ren_partial_preserve.
            rewrite ren_butLast_distribute in B6. rewrite B6.
            destruct (IHtailrec (y) u.[ren(+1)] xiA xi1 xi2)
              as [IH1 [IH2 IH3]].
            constructor.
            apply tailrec_subst_trace_compose1 with (n:= 1); eauto using simulate_shift.
            apply trace_partial_prefix2; eauto.
            apply IH1; eauto. omega.
          - apply not_partial_total in n0.
            assert (y= 0).
            { destruct y; eauto. inv B5. inv H4. }
            rewrite H3 in B3. asimpl in B3.
            assert (TC (CFPFix (linearize (S n) s u.[ren (+1)])) xiB).
            { apply IHm; eauto.
              - rewrite B6 in H1. apply boundT_concat_decompose_right with (xi1:= butLast (ren_trace shift xiA)); eauto using butLast_total_preserve, ren_total_preserve.
              - rewrite B6 in H2.
                apply concat_partial_compose with (xi1:= butLast (ren_trace shift xiA)); eauto using butLast_total_preserve, ren_total_preserve. }
            destruct (IHtailrec (0) u.[ren(+1)] xiA xi1 xi2)
              as [IH1 [IH2 IH3]].
            assert (TC (linearize (S n) s u.[ren (+1)]) xiA).
            { apply IH1; eauto; try omega. rewrite H3 in B4. eauto. }
            rewrite B6. constructor. apply tailrec_subst_trace_compose2 with (x:= 0) (n:= 1); eauto using simulate_shift. rewrite H3 in B4. eauto. }
    + apply Fix_unfold_subsume in H0. destruct H0 as [m H0]. general induction m; simpl in H0.
      × apply Null_trace in H0. rewrite H0. eauto using TC.
      × apply TC_TCsubst in H0.
        destruct (@tailrec_subst_trace_decompose 1 s (unfold s m .: ids) shift xi1) as [[xiA [A1 [A2 A3]]] | [xiA [xiB [y [B2 [B3 [B4 [B5 [B6 B7]]]]]]]]]; eauto using simulate_shift.
        { apply tailrec_step with (n:= S n); eauto. omega. }
        { destruct (IHtailrec (0) u.[ren(+1)] xiA xiA (ren_trace (+1) xi2)) as [IH1 [IH2 IH3]].
          constructor. rewrite A2. setoid_rewrite ren_trace_id_inc_shift at 4.
          rewrite <- ren_concat_distribute.
          apply tailrec_subst_trace_compose1 with (n:= 1); eauto using simulate_shift.
          - apply IH3; eauto.
            + rewrite A2 in H1. apply ren_total_origin with (f:= shift); eauto.
            + rewrite A2 in H2. apply boundT_ren_shift_reconstruct; eauto.
            + apply ren_trace_ren. eauto.
          - apply boundT_concat_compose; eauto. apply boundT_ren_lift. }
        { assert (y = 0).
          { destruct y; eauto. inv B5. inv H5. }
          subst. asimpl in B3.
          assert (TC (CFPFix (linearize (S n) s u.[ren (+1)])) (concat xiB xi2)).
          { apply concat_total_decompose in H1. destruct H1. apply IHm; eauto using boundT_concat_decompose_right. }
          destruct (IHtailrec (0) u.[ren(+1)] xiA xiA (ren_trace (+1) xi2)) as [IH1 [IH2 IH3]].
          assert (TC (linearize (S n) s u.[ren (+1)]) xiA).
          { apply IH1; eauto. omega. }
          rewrite concat_assoc. constructor.
          apply tailrec_subst_trace_compose2 with (x:= 0) (n:= 1); eauto using simulate_shift. }
Qed.

Trace deconstruction of linearized programs


Lemma linearize_correct2 n s u xi
  : TC (linearize n s u) xi
    → tailrec n s
    → tailrec n u
    → (TC s xi partial xi boundT n xi)
        (TC s xi x, x < n terminal x xi)
        ( xi1 xi2, xi = concat xi1 xi2 TC s xi1 total xi1 boundT n xi1 TC u xi2).
Proof.
  intros. general induction H0; simpl in H.
  - right. right. T, xi. repeat split; eauto using TC, total, boundT.
  - decide (m < n).
    + inv H.
      × left. repeat split; eauto using TC, partial, boundT.
      × right. left. split; eauto. m. split; eauto using terminal.
      × right. left. split; eauto. m. split; eauto using terminal.
    + assert (n m); try omega. inv H.
      × left. repeat split; eauto using TC, partial, boundT.
      × decide (partial xi1).
        { left. rewrite concat_partial_absorb_right; eauto. split; repeat split; eauto.
          inv H4; eauto using boundT. }
        { right. right. xi1, xi2. repeat split; eauto using not_partial_total.
          inv H4; eauto using boundT. }
  - inv H.
    + left. repeat split; eauto using TC, partial, boundT.
    + destruct (IHtailrec1 u xi H4 H1) as [[A1 [A2 A3]] | [[B1 [x [B2 B3]] ] | [xiA [xiB [C1a [C2a [C3a [C4a C5a]]]]]]]]; eauto.
      × left. split; eauto using TC.
      × right. left. split; eauto using TC.
      × right. right. xiA, xiB. split; eauto using TC.
    + destruct (IHtailrec2 u xi H4 H1) as [[A1 [A2 A3]] | [[B1 [x [B2 B3]] ] | [xiA [xiB [C1a [C2a [C3a [C4a C5a]]]]]]]]; eauto.
      × left. split; eauto using TC.
      × right. left. split; eauto using TC.
      × right. right. xiA, xiB. split; eauto using TC.
  - simpl in H0. destruct (IHtailrec1 (linearize n t u) xi H0) as [ [A1 [A2 A3]] | [[B1 [x [B2 B3]] ] | [xi1 [xi2 [C1 [C2 [C3 [C4 C5]]]]]]]].
    + apply linearize_tailrec; eauto.
    + left. split; eauto using trace_partial_Seq_left.
    + assert (boundT n xi).
      { apply bound_boundT with (s:= s); eauto. }
      exfalso. apply terminal_boundT_contradict with (n:= n) (xi:= xi) (x:= x); eauto.
    + destruct (IHtailrec2 u xi2 C5 H1) as [ [A1 [A2 A3]] | [[B1 [x [B2 B3]] ] | [xiA [xiB [C1a [C2a [C3a [C4a C5a]]]]]]]]; eauto.
       × left. rewrite C1. repeat split; eauto using TC, concat_partial_preserve_right, boundT_concat_compose.
       × right. left. rewrite C1. split; eauto using TC.
          x. split; eauto. apply terminal_concat_compose with (n:= n); eauto.
       × right. right. (concat xi1 xiA), xiB.
         rewrite C1. rewrite C1a. repeat split; eauto using concat_assoc, TC, concat_total_compose, boundT_concat_compose.
  - apply Fix_unfold_subsume in H. destruct H as [m H]. general induction m; simpl in H.
    + apply Null_trace in H. left. rewrite H. repeat split; eauto using TC, partial, boundT.
    + apply TC_TCsubst in H.
      assert (tailrec (S n) (linearize (S n) s u.[ren (+1)])); eauto using linearize_tailrec, tailrec_lift.
      assert (tailrec 1 (linearize (S n) s u.[ren (+1)])).
      { apply tailrec_step with (n:= S n); eauto. omega. }
      apply tailrec_subst_trace_decompose with (sigma:= unfold (linearize (S n) s u.[ren (+1)]) m .: ids) (f:= shift) (xi:= xi) in H3; eauto using simulate_shift.
      destruct H3 as [[xi' [A1 [A2 A3]]]| [xi1 [xi2 [x [B2 [B3 [B4 [B5 [B6 B7]]]]]]]]].
      × destruct (IHtailrec (u.[ren(+1)]) xi') as [[A1a [A2a A3a]] | [[B1a [x [B2a B3a]] ] | [xi1 [xi2 [C1a [C2a [C3a [C4a C5a]]]]]]]]; eauto using tailrec_lift.
        { left. split.
          - constructor. rewrite A2. apply tailrec_subst_trace_compose1 with (n:= 1); eauto using simulate_shift.
          - rewrite A2. split; eauto using ren_partial_preserve, boundT_ren_shift_preserve. }
        { right. left. split.
          - constructor. rewrite A2. apply tailrec_subst_trace_compose1 with (n:= 1); eauto using simulate_shift.
          - destruct x.
            + exfalso. apply terminal_boundT_contradict with (n:= 1) (xi:= xi') (x:= 0); eauto.
            + x. split; try omega.
              rewrite A2. apply terminal_ren_shift_preserve; eauto. }
        { right. right. (ren_trace shift xi1), (ren_trace shift xi2).
          split.
          - rewrite A2. rewrite C1a. rewrite ren_concat_distribute. eauto.
          - split.
            + constructor. apply tailrec_subst_trace_compose1 with (n:= 1); eauto using simulate_shift.
              apply boundT_step with (n:= S n); eauto. omega.
            + repeat split; eauto using ren_total_preserve, boundT_ren_shift_preserve.
              rewrite (@ id_shift u). apply ren_trace_ren. eauto. }
      × destruct (IHtailrec (u.[ren(+1)]) xi1) as [[A1a [A2a A3a]] | [[B1a [y [B2a B3a]] ] | [xiA [xiB [C1a [C2a [C3a [C4a C5a]]]]]]]]; eauto using tailrec_lift.
        { exfalso. apply terminal_boundT_contradict with (n:= S n) (xi:= xi1) (x:= x); eauto. omega. }
        { assert (x = y); eauto using terminal_unique.
          assert (x = 0).
          { destruct x; eauto. exfalso. omega. }
          decide (partial xi1).
          - assert (xi = ren_trace shift (butLast xi1)).
            { rewrite B6. rewrite concat_partial_absorb_right; eauto using ren_butLast_distribute, butLast_partial_preserve, ren_partial_preserve. }
            left. split.
            + rewrite H5. constructor.
              apply tailrec_subst_trace_compose1 with (n:= 1); eauto using trace_partial_prefix2, simulate_shift.
            + rewrite H5. split; eauto using ren_partial_preserve, butLast_partial_preserve.
              apply tailrec_tailrec_trace with (n:= S n) in B1a; eauto using boundT_ren_shift_preserve, tailrec_trace_butLast_boundT.
          - apply not_partial_total in n0.
            assert (boundT (S n) (butLast xi1)).
            { apply tailrec_tailrec_trace with (n:= S n) in B1a; eauto using tailrec_trace_butLast_boundT. }
            destruct (IHm n s H0 IHtailrec u xi2) as [[A1b [A2b A3b]] | [[B1b [z [B2b B3b]] ] | [xiA [xiB [C1b [C2b [C3b [C4b C5b]]]]]]]]; eauto.
            + rewrite H4 in B3. asimpl in B3. eauto.
            + left. split.
              × constructor. rewrite B6. apply tailrec_subst_trace_compose2 with (x:= 0) (n:= 1); eauto using simulate_shift.
                rewrite <- H3 in B3a. rewrite H4 in B3a. eauto.
              × rewrite B6. split; eauto using concat_partial_preserve_right.
                apply boundT_concat_compose; eauto. rewrite ren_butLast_distribute.
                apply boundT_ren_shift_preserve. eauto.
            + right. left. split.
              × constructor. rewrite B6. apply tailrec_subst_trace_compose2 with (x:= 0) (n:= 1); eauto using simulate_shift.
                rewrite <- H3 in B3a. rewrite H4 in B3a. eauto.
              × z. split; eauto. rewrite B6. apply terminal_concat_compose with (n:= n); eauto.
                { rewrite ren_butLast_distribute. apply boundT_ren_shift_preserve. eauto. }
                { eauto using butLast_total_preserve, ren_total_preserve. }
            + right. right. (concat (butLast (ren_trace shift xi1)) xiA), xiB.
              rewrite B6, C1b. split; eauto using concat_assoc. split.
              × constructor. apply tailrec_subst_trace_compose2 with (x:= 0) (n:= 1); eauto using simulate_shift. rewrite <- H3 in B3a. rewrite H4 in B3a. eauto.
              × split.
                { apply concat_total_compose; eauto using butLast_total_preserve, ren_total_preserve. }
                { split; eauto. apply boundT_concat_compose; eauto.
                  rewrite ren_butLast_distribute. eauto using boundT_ren_shift_preserve. } }
        { assert (terminal x xiB).
          { apply terminal_concat_decompose_right with (n:= S n) (xiA := xiA); eauto.
            - rewrite <- C1a. eauto.
            - omega. }
          exfalso. apply terminal_boundT_contradict with (n:= 1) (xi:= xiB) (x:= x); eauto.
          apply bound_boundT with (s:= u.[ren(+1)]); eauto.
          apply bound_ren. intros. left. simpl. omega. }
Qed.

Correctness


Lemma linearize_correct s u
  : tailrec 0 s
    → lin 0 u
    → CFPSeq s u =T linearize 0 s u.
Proof.
  intros. split; intros.
  - inv H1; eauto using TC.
     destruct linearize_correct1 with (n:= 0) (u:= u) (xi2:= xi2) (x:= 0) (s:= s) (xi1:= xi1) (xi:= xi1) as [A1 [A2 A3]]; eauto.
     decide (partial xi1).
     + rewrite concat_partial_absorb_right; eauto.
       apply A2; eauto. apply boundT_zero.
     + apply not_partial_total in n. apply A3; eauto.
       apply boundT_zero.
  - apply linearize_correct2 in H1; eauto using lin_tailrec.
    destruct H1 as [[A1 [A2 A3]] | [[B1 [x [B2 B3]]] | [xi1 [xi2 [C1 [C2 [C3 [C4 C5]]]]]]]].
    + apply trace_partial_Seq_left; eauto.
    + inv B2.
    + rewrite C1. constructor; eauto.
Qed.

Theorem linearize_correct_final s u
  : tailrec 0 s
    → lin 0 u
    → CFPSeq s u =T linearize 0 s u
        lin 0 (linearize 0 s u).
Proof.
  intros. split; eauto using linearize_correct, linearize_lin.
Qed.