Library Imp_LangTrick.LogicProp.LogicPropTheorems

From Coq Require Import Arith Psatz List String.
From Imp_LangTrick Require Import LogicProp StackLangTheorems.

Adequacy theorems for the higher-order relations and functions on LogicProps

Lemma transform_prop_exprs_args_adequacy_forward :
  forall (V A: Set) (l l': list A) (phi: A -> A) (psi: A -> A -> Prop),
    (forall (a1 a2: A),
        a2 = phi a1 <->
          psi a1 a2) ->
    l' = map phi l ->
    transformed_prop_exprs_args (V := V) psi l l'.
Proof.
  intros V A l.
  induction l; intros.
  - simpl in H0. subst. econstructor.
  - simpl in H0. rewrite H0. econstructor.
    eapply H. reflexivity.
    eapply IHl; eauto.
Defined.

Lemma transform_prop_exprs_args_adequacy_backward :
  forall (V A: Set) (l l': list A) (phi: A -> A) (psi: A -> A -> Prop),
    (forall (a1 a2: A),
        a2 = phi a1 <->
          psi a1 a2) ->
    transformed_prop_exprs_args (V := V) psi l l' ->
    l' = map phi l.
Proof.
  intros V A l.
  induction l; intros.
  - simpl. invs H0. reflexivity.
  - invs H0. simpl. f_equal.
    + eapply H. assumption.
    + eapply IHl; eassumption.
Qed.

Lemma transform_prop_exprs_adequacy_forward :
  forall (V A: Set) (l l': LogicProp V A) (phi: A -> A) (psi: A -> A -> Prop),
    (forall (a1 a2: A),
        a2 = phi a1 <->
          psi a1 a2) ->
    l' = transform_prop_exprs l phi ->
    transformed_prop_exprs psi l l'.
Proof.
  intros V A.
  induction l; intros;
    match goal with
    | [ H : ?l' = transform_prop_exprs ?l ?phi |- _ ] =>
        simpl in H; rewrite H
    end.
  - econstructor.
  - econstructor.
  - econstructor. eapply H. reflexivity.
  - econstructor; eapply H; reflexivity.
  - econstructor; first [ eapply IHl1 | eapply IHl2 ]; eauto.
  - econstructor; first [ eapply IHl1 | eapply IHl2 ]; eauto.
  - econstructor; eapply H; reflexivity.
  - econstructor. eapply transform_prop_exprs_args_adequacy_forward; eauto.
Defined.

Lemma transform_prop_exprs_adequacy_backward :
  forall (V A: Set) (l l': LogicProp V A) (phi: A -> A) (psi: A -> A -> Prop),
    (forall (a1 a2: A),
        a2 = phi a1 <->
          psi a1 a2) ->
    transformed_prop_exprs psi l l' ->
    l' = transform_prop_exprs l phi.
Proof.
  intros V A.
  induction l; intros;
    match goal with
    | [ H : transformed_prop_exprs ?psi ?l ?l' |- _ ] =>
        invs H
    end; simpl; f_equal; try (first [ eapply H | eapply IHl | eapply IHl1 | eapply IHl2 ]; eassumption).
  eapply transform_prop_exprs_args_adequacy_backward; eassumption.
Qed.

Lemma compile_prop_args_adequacy_forward :
  forall (A B: Set) (args: list A) (args': list B) (phi: A -> B),
    args' = map phi args ->
    compile_prop_args_rel phi args args'.
Proof.
  induction args; intros; simpl in H; rewrite H; econstructor.
  invs H.
  eapply IHargs.
  eauto.
Qed.

Lemma compile_prop_args_adequacy_backward :
  forall (A B: Set) (args: list A) (args': list B) (phi: A -> B),
    compile_prop_args_rel phi args args' ->
    args' = map phi args.
Proof.
  induction args; intros; invs H; simpl; try eauto.
  f_equal; try eauto.
Qed.

Lemma compile_prop_adequacy_forward :
  forall (V A B: Set) (l: LogicProp V A) (l': LogicProp V B) (phi: A -> B),
    l' = compile_prop l phi ->
    compile_prop_rel phi l l'.
Proof.
  induction l; intros; simpl in H; rewrite H; econstructor;
    try (first [eapply IHl | eapply IHl1 | eapply IHl2]; eauto).
  invs H.
  eapply compile_prop_args_adequacy_forward; eauto.
Qed.

Lemma compile_prop_adequacy_backward :
  forall (V A B: Set) (l: LogicProp V A) (l': LogicProp V B) (phi: A -> B),
    compile_prop_rel phi l l' ->
    l' = compile_prop l phi.
Proof.
  induction l; intros; invs H; simpl; try eauto; f_equal;
    try (first [eapply IHl | eapply IHl1 | eapply IHl2]; eauto).
  eapply compile_prop_args_adequacy_backward. assumption.
Qed.

Theorem compile_prop_args_adequacy :
  forall (A B: Set) (args: list A) (args': list B) (phi: A -> B),
    args' = map phi args <->
      compile_prop_args_rel phi args args'.
Proof.
  split; intros;
    first [eapply compile_prop_args_adequacy_backward | eapply compile_prop_args_adequacy_forward];
    eauto.
Qed.

Theorem compile_prop_adequacy :
  forall (V A B: Set) (l: LogicProp V A) (l': LogicProp V B) (phi: A -> B),
    l' = compile_prop l phi <->
      compile_prop_rel phi l l'.
Proof.
  split; intros;
    first [eapply compile_prop_adequacy_backward | eapply compile_prop_adequacy_forward];
    eauto.
Qed.

Lemma pcompile_prop_args_rel_adequacy_forward :
  forall (A B: Set) (args: list A) (args': list B) (phi: A -> B) (psi: A -> B -> Prop),
    (forall (a: A) (b: B),
        b = phi a <->
          psi a b) ->
    compile_prop_args_rel phi args args' ->
    pcompile_args_rel psi args args'.
Proof.
  induction args; intros; invs H0; econstructor.
  - eapply H. eauto.
  - eapply IHargs; eauto.
Qed.

Lemma pcompile_prop_rel_adequacy_forward :
  forall (V A B: Set) (l: LogicProp V A) (l': LogicProp V B) (phi: A -> B) (psi: A -> B -> Prop),
    (forall (a: A) (b: B),
        b = phi a <->
          psi a b) ->
    compile_prop_rel phi l l' ->
    pcompile_rel psi l l'.
Proof.
  induction l; intros; invs H0; econstructor;
    try (first [eapply IHl | eapply IHl1 | eapply IHl2]; eauto);
    try (eapply H; eauto).
  eapply pcompile_prop_args_rel_adequacy_forward; eauto.
Qed.

Lemma pcompile_prop_args_rel_adequacy_backward :
  forall (A B: Set) (args: list A) (args': list B) (phi: A -> B) (psi: A -> B -> Prop),
    (forall (a: A) (b: B),
        b = phi a <->
          psi a b) ->
    pcompile_args_rel psi args args' ->
    compile_prop_args_rel phi args args'.
Proof.
  induction args; intros; invs H0; try econstructor.
  eapply IHargs in H6; [ | eassumption ].
  eapply H in H4. rewrite H4. econstructor.
  assumption.
Qed.

Lemma pcompile_prop_rel_adequacy_backward :
  forall (V A B: Set) (l: LogicProp V A) (l': LogicProp V B) (phi: A -> B) (psi: A -> B -> Prop),
    (forall (a: A) (b: B),
        b = phi a <->
          psi a b) ->
    pcompile_rel psi l l' ->
    compile_prop_rel phi l l'.
Proof.
  induction l; intros; invs H0; try econstructor;
    try repeat match goal with
    | [ psi: ?A -> ?B -> Prop,
        Hpsi : ?psi ?a ?b |- _ ] =>
        eapply H in Hpsi; rewrite Hpsi
               end; try econstructor; try eauto.
  eapply pcompile_prop_args_rel_adequacy_backward; eauto.
Qed.

Theorem pcompile_prop_args_rel_adequacy :
  forall (A B: Set) (args: list A) (args': list B) (phi: A -> B) (psi: A -> B -> Prop),
    (forall (a: A) (b: B),
        b = phi a <->
          psi a b) ->
    compile_prop_args_rel phi args args' <->
      pcompile_args_rel psi args args'.
Proof.
  split; intros;
    first [eapply pcompile_prop_args_rel_adequacy_forward | eapply pcompile_prop_args_rel_adequacy_backward];
    eauto.
Qed.

Theorem pcompile_prop_rel_adequacy :
  forall (V A B: Set) (l: LogicProp V A) (l': LogicProp V B) (phi: A -> B) (psi: A -> B -> Prop),
    (forall (a: A) (b: B),
        b = phi a <->
          psi a b) ->
    compile_prop_rel phi l l' <->
    pcompile_rel psi l l'.
Proof.
  split; intros;
    first [eapply pcompile_prop_rel_adequacy_forward | eapply pcompile_prop_rel_adequacy_backward];
    eauto.
Qed.

Theorem pcompile_compile_args_adequacy :
  forall (A B: Set) (args: list A) (args': list B) (phi: A -> B) (psi: A -> B -> Prop),
    (forall (a: A) (b: B),
        b = phi a <->
          psi a b) ->
    args' = map phi args <->
      pcompile_args_rel psi args args'.
Proof.
  split; intros.
  - eapply pcompile_prop_args_rel_adequacy; try eauto.
    eapply compile_prop_args_adequacy.
    assumption.
  - eapply compile_prop_args_adequacy.
    eapply pcompile_prop_args_rel_adequacy; try eauto.
Qed.

Theorem pcompile_compile_adequacy :
  forall (V A B: Set) (l: LogicProp V A) (l': LogicProp V B) (phi: A -> B) (psi: A -> B -> Prop),
    (forall (a: A) (b: B),
        b = phi a <->
          psi a b) ->
    l' = compile_prop l phi <->
      pcompile_rel psi l l'.
Proof.
  split; intros.
  - eapply pcompile_prop_rel_adequacy; try eauto.
    eapply compile_prop_adequacy.
    eassumption.
  - eapply compile_prop_adequacy.
    eapply pcompile_prop_rel_adequacy; try eauto.
Qed.

Lemma eval_prop_args_adequacy_forward :
  forall (V A: Set) (args: list A) (args': list V) (phi: A -> V) (psi: A -> V -> Prop),
    (forall (v: V) (a: A),
        v = phi a <->
          psi a v) ->
    args' = map phi args ->
    eval_prop_args_rel psi args args'.
Proof.
  induction args; intros; simpl in H0; rewrite H0; try econstructor.
  - eapply H. reflexivity.
  - eapply IHargs; try eauto.
Qed.

Definition fun_rel_adequate {A B: Set} (phi: A -> B) (psi: A -> B -> Prop): Prop :=
  forall (a: A) (b: B),
    b = phi a <->
      psi a b.

Lemma eval_prop_adequacy_forward :
  forall (V A: Set) (l: LogicProp V A) (phi: A -> V) (psi: A -> V -> Prop),
    fun_rel_adequate phi psi ->
    eval_prop l phi ->
    eval_prop_rel psi l.
Proof.
  induction l; intros; unfold fun_rel_adequate in *; simpl in H0.
  - econstructor.
  - invs H0.
  - econstructor.
    + eapply H. eauto.
    + eauto.
  - econstructor.
    + eapply H. eauto.
    + eapply H; eauto.
    + eauto.
  - econstructor; destruct H0; eauto.
  - destruct H0; [econstructor | eapply RelOrPropRight]; eauto.
  - econstructor; try eapply H; eauto.
  - econstructor.
    eapply eval_prop_args_adequacy_forward; eauto.
    eauto.
Qed.

Lemma eval_prop_args_adequacy_backward :
  forall (V A: Set) (args: list A) (args': list V) (phi: A -> V) (psi: A -> V -> Prop),
    (forall (v: V) (a: A),
        v = phi a <->
          psi a v) ->
    eval_prop_args_rel psi args args' ->
    args' = map phi args.
Proof.
  induction args; intros; invs H0; try econstructor.
  simpl.
  f_equal.
  - eapply H. assumption.
  - eapply IHargs; eauto.
Qed.

Lemma eval_prop_adequacy_backward :
  forall (V A: Set) (l: LogicProp V A) (phi: A -> V) (psi: A -> V -> Prop),
    fun_rel_adequate phi psi ->
    eval_prop_rel psi l ->
    eval_prop l phi.
Proof.
  induction l; intros; invs H0;
  match goal with
  | [ |- eval_prop (OrProp _ _ _ _) _ ] =>
      idtac
  | _ => try econstructor
            end; simpl; unfold fun_rel_adequate in *;
    try repeat match goal with
               | [ psi: ?A -> ?B -> Prop,
                     Hpsi : ?psi ?a ?b |- _ ] =>
                   eapply H in Hpsi; rewrite Hpsi in *; eauto
               end.
  - eapply IHl1; eauto.
  - eapply IHl2; eauto.
  - left. eapply IHl1; eauto.
  - right. eapply IHl2; eauto.
  - eapply eval_prop_args_adequacy_backward in H4. erewrite <- H4. eassumption. eauto.
Qed.

Theorem eval_prop_args_adequacy :
  forall (V A: Set) (args: list A) (args': list V) (phi: A -> V) (psi: A -> V -> Prop),
    (forall (v: V) (a: A),
        v = phi a <->
          psi a v) ->
    args' = map phi args <->
    eval_prop_args_rel psi args args'.
Proof.
  split; intros;
    first [eapply eval_prop_args_adequacy_forward | eapply eval_prop_args_adequacy_backward];
    eauto.
Qed.

Lemma eval_prop_adequacy :
  forall (V A: Set) (l: LogicProp V A) (phi: A -> V) (psi: A -> V -> Prop),
    fun_rel_adequate phi psi ->
    eval_prop l phi <->
      eval_prop_rel psi l.
Proof.
  split; intros;
    first [eapply eval_prop_adequacy_forward | eapply eval_prop_adequacy_backward];
    eauto.
Qed.

Section fun_rel_implies.
  Variable V A: Set.


  Let fun_rel_implies (phi phi': A -> Prop) :=
        forall (a: A),
          phi a -> phi' a.

  Variable phi phi': A -> Prop.

  Lemma prop_rel_args_implies :
    forall (alist: list A),
      fun_rel_implies phi phi' ->
      prop_args_rel (V := V) phi alist ->
      prop_args_rel (V := V) phi' alist.
  Proof.
    induction alist; intros.
    - constructor.
    - invs H0. constructor.
      + eapply H. assumption.
      + eapply IHalist; assumption.
  Qed.

  Lemma prop_rel_implies :
    forall (a: LogicProp V A),
    forall (IMP: fun_rel_implies phi phi')
      (PROP: prop_rel phi a),
      prop_rel phi' a.
  Proof.
    induction a; intros; invs PROP; try constructor; try (eapply IMP; assumption); eauto.
    - eapply prop_rel_args_implies; assumption.
  Qed.
End fun_rel_implies.