From Undecidability.Shared.Libs.DLW
  Require Import utils finite pos vec.

From Undecidability.MuRec
  Require Import recalg ra_bs recursor minimizer ra_ca.

Set Implicit Arguments.

Set Default Proof Using "Type".

Notation "[| f |]" := (@ra_rel _ f) (at level 0).

Section soundness_and_completeness.


  Lemma ra_ca_inc_bs k (f : recalg k) v x : ( n, [f;v] -[n>> x) [f;v] ~~> x.
  Proof.
    intros (n & H); revert H.
    induction 1 as [ n v | v | v
                   | k v p
                   | k i f gj v n w q x
                   | k f g v n x
                   | k f g v n p x q y
                   | k f v p n w q ]; try (constructor; auto; fail).
    apply in_ra_bs_comp with w; auto.
    apply in_ra_bs_rec_S with x; auto.
    apply in_ra_bs_min with w; auto.
  Qed.



  Lemma ra_bs_inc_rel k (f : recalg k) v x : [f;v] ~~> x [|f|] v x.
  Proof.
    induction 1 as [ n v | v | v
                   | k v p
                   | k i f gj v w x
                   | k f g v n x
                   | k f g v n x y
                   | k f v n w ]; try reflexivity.
    exists w; split; auto; intros; rewrite vec_pos_set; auto.
    red; unfold s_rec; simpl; auto.
    rewrite ra_rel_fix_rec in |- *; unfold s_rec in |- *.
    simpl in |- *; exists x; auto.
    rewrite ra_rel_fix_min; unfold s_min; split; auto.
    intros y Hy.
    exists (vec_pos w (nat2pos Hy)).
    generalize ( (nat2pos Hy)).
    rewrite pos2nat_nat2pos.
    eqgoal; do 2 f_equal.
  Qed.



  Lemma ra_rel_inc_ca k (f : recalg k) v x : [|f|] v x n, [f;v] -[n>> x.
  Proof.
    revert v x; induction f as [ k | | | k p | k i f gj Hf Hgj
                               | k f g Hf Hg
                               | ]; intros v x.
    rewrite ra_rel_fix_cst; unfold s_cst; intros []; exists 1; constructor.
    rewrite ra_rel_fix_zero; unfold s_zero; intro; subst; exists 1; constructor.
    rewrite ra_rel_fix_succ; unfold s_succ; intro; subst; exists 1; constructor.
    rewrite ra_rel_fix_proj; unfold s_proj; intros []; exists 1; constructor.

    rewrite ra_rel_fix_comp; unfold s_comp; intros (w & & ).
    apply Hf in ; destruct as (n & ).
    assert ( p, n, [vec_pos gj p;v] -[n>> vec_pos w p) as .
      intros p; specialize ( p); rewrite vec_pos_map in ; auto.
    apply vec_reif in .
    destruct as (m & Hm).
    exists (1+n+vec_sum m).
    apply in_ra_ca_comp with (2 := ); auto.

    rewrite ra_rel_fix_rec; unfold s_rec.
    rewrite (vec_head_tail v); simpl; generalize (vec_head v) (vec_tail v).
    clear v; intros i v.
    revert x; induction i as [ | i IHi ]; intros x; simpl.
    intros H; apply Hf in H; destruct H as (n & Hn); exists (S n); constructor; auto.
    intros (y & & ).
    apply IHi in ; destruct as (n & Hn).
    apply Hg in ; destruct as (m & Hm).
    exists (1+n+m); apply in_ra_ca_rec_S with (1 := Hn); auto.

    rewrite ra_rel_fix_min; unfold s_min; intros ( & ).
    assert ( (p : pos x), r, [|f|] (pos2nat p##v) (S r)) as .
      intros p; apply ( _ (pos2nat_prop p)).
    apply vec_reif in .
    destruct as (w & Hw).
    assert ( p, n, [f;pos2nat p##v] -[n>> S (vec_pos w p)) as .
      intros p; apply IHf, Hw.
    apply vec_reif in .
    destruct as (m & Hm).
    apply IHf in .
    destruct as (n & Hn).
    exists (1+n+vec_sum m).
    apply in_ra_ca_min with (1 := Hm); auto.
  Qed.



  Hint Resolve ra_ca_inc_bs ra_bs_inc_rel ra_rel_inc_ca : core.

  Theorem ra_bs_correct k (f : recalg k) v x : [|f|] v x [f;v] ~~> x.
  Proof. split; auto. Qed.

  Theorem ra_ca_correct k (f : recalg k) v x : [|f|] v x n, [f;v] -[n>> x.
  Proof. split; auto. Qed.

End soundness_and_completeness.