Library CharacteristicLogics

Require Import SfLib.
Require Import LibTactics.
Require Import BisimTheory.

Section HML_DecoupledBisimulation.
  Variable lts: labeled_transition_system.
  Import Stepping.
  Require Import ClassicalFacts.

  Inductive phiA : Type :=
  | top: phiA
  | conj: phiAphiAphiA
  | all: list lts_LphiEphiA
  with phiE: Type :=
  | bot: phiE
  | disj: phiEphiEphiE
  | ext: list lts_LphiAphiE
  .

  Inductive phi : Type :=
  | phi1: phiAphi
  | phi2: phiEphi.

  Fixpoint forcesA (p:lts_S) (f:phiA) : Prop := match f with
  | topTrue
  | conj f1 f2forcesA p f1 forcesA p f2
  | all la f p', step_star p la p'forcesE p' f
  end
  with forcesE (p:lts_S) (f:phiE) : Prop := match f with
  | botFalse
  | disj f1 f2forcesE p f1 forcesE p f2
  | ext la f p', step_star p la p' forcesA p' f
  end.

  Definition topE:= (ext nil top).
  Definition botA:= (all nil bot).

  Fixpoint negA f := match f with
  | topbot
  | conj f1 f2disj (negA f1) (negA f2)
  | all la f1ext la (negE f1)
  end
  with negE f := match f with
  | bottop
  | disj f1 f2conj (negE f1) (negE f2)
  | ext la f1all la (negA f1)
  end.

  Lemma topE_correct: p, forcesE p topE forcesA p top.
  Proof.
    simpl; split; intros.
    auto.
     p; split; auto. apply step_nil.
  Qed.

  Lemma botA_correct: p, forcesA p botA forcesE p bot.
  Proof.
    simpl; split; intros; auto.
    eapply H; apply step_nil.
  Qed.

  Lemma negA_correct1: p f, forcesE p (negA f) → ¬forcesA p f
  with negE_correct1: p f, forcesA p (negE f) → ¬forcesE p f.
  Proof.
    × induction f; simpl; intros.
    - intuition.
    - intuition.
    - intro.
    destruct H as [p'[??]].
    apply H0 in H.
    eapply negE_correct1; eauto.
    × induction f; simpl; intros.
    intuition.
    intuition.
    intros [p'[??]].
    apply H in H0.
    eapply negA_correct1; eauto.
  Qed.

  Fixpoint list_conjA (lf: list phiA) := match lf with
  | niltop
  | f::lf'conj f (list_conjA lf')
  end.

  Lemma f_list_conjA: p lf,
    forcesA p (list_conjA lf) ( f, In f lfforcesA p f).
  Proof.
    induction lf; simpl; intros.
    × intuition.
    × setoid_rewrite IHlf. intuition. subst; eauto.
  Qed.

  Fixpoint list_disjE (lf: list phiE) := match lf with
  | nilbot
  | f::lf'disj f (list_disjE lf')
  end.

  Lemma f_list_disjE: p lf,
    forcesE p (list_disjE lf) ( f, In f lf forcesE p f).
  Proof.
    induction lf; simpl; intros.
    × intuition. destruct H as [?[??]]; auto.
    × setoid_rewrite IHlf. clear IHlf. intuition. subst; eauto.
    destruct H0 as [?[??]]; eauto.
    destruct H as [?[[?|?]?]]; subst; eauto.
  Qed.

  Delimit Scope scopeA with scopeA.
  Delimit Scope scopeE with scopeE.
  Delimit Scope forces_scope with fores.
  Notation "¬ f" := (negA f%scopeA) (at level 31, right associativity) : scopeE.
  Notation "¬ f" := (negE f%scopeE) (at level 31, right associativity) : scopeA.
  Notation "f1 ∧ f2" := (conj f1%scopeA f2%scopeA) (at level 41, right associativity) : scopeA.
  Notation "f1 ∨ f2" := (disj f1%scopeE f2%scopeE) (at level 51, right associativity) : scopeE.
  Notation "〈 la 〉 f" := (ext la f%scopeA) (at level 31, right associativity, format "〈 la 〉 f") : scopeE.
  Notation "⦋ la ⦌ f" := (all la f%scopeE) (at level 31, right associativity, format "⦋ la ⦌ f") : scopeA.
  Notation "p ⊨ᴱ f" := (forcesE p f%scopeE) (at level 100, no associativity) : forces_scope.
  Notation "p ⊨ᴬ f" := (forcesA p f%scopeA) (at level 100, no associativity) : forces_scope.
  Open Scope forces_scope.


  Fixpoint forces (p:lts_S) (f:phi) : Prop := match f with
  | phi1 fforcesA p f
  | phi2 fforcesE p f
  end.

  Definition image_finite_R {A:Type} (R: AAProp) := a,
     (la' : list A), ( a', R a a' In a' la').

  Definition image_finite (lts:labeled_transition_system) :=
    ( a, image_finite_R (fun p p'lstep p a p')) image_finite_R tstep.

  Definition weakly_image_finite (lts:labeled_transition_system) :=
    ( la, image_finite_R (fun p p'step_star p la p')).

  Ltac by_contradiction:=
  match goal with
  | [H: excluded_middle |- ?G] ⇒ destruct (H G); auto; false
  end.

  Definition hml_implA p q:= f, forcesA p fforcesA q f.
  Definition hml_implE p q:= f, forcesE p fforcesE q f.

  Definition hml_equivA p q := hml_implA p q hml_implA q p.
  Definition hml_equivE p q := hml_implE p q hml_implE q p.
  Definition hml_equiv p q := hml_equivA p q hml_equivE p q.

  Lemma pcsim_hmlA: f p q,
    partial_contrasimilar q pforcesA p fforcesA q f
  with pcsim_hmlE: f p q,
    partial_contrasimilar p qforcesE p fforcesE q f.
  Proof.
    × induction f; try rename p into f; simpl; intros; auto.
    - destruct H0; eauto.
    - rename p' into q'.
    edestruct step_star_pcsim as [p'[??]]; eauto.
    × induction f; try rename p into f; simpl; intros; auto.
    - destruct H0; eauto.
    - destruct H0 as [p'[??]].
    edestruct step_star_pcsim as [q'[??]]; eauto.
  Qed.

  Lemma csim_hmlA: p q,
    contrasimilar p qhml_equivA p q.
  Proof.
    split; intros; intro f; intros; eapply pcsim_hmlA; eauto.
    apply csim_pcsim2; auto.
    apply csim_pcsim1; auto.
  Qed.

  Lemma csim_hmlE: p q,
    contrasimilar p qhml_equivE p q.
  Proof.
    split; intros; intro f; intros; eapply pcsim_hmlE; eauto.
    apply csim_pcsim1; auto.
    apply csim_pcsim2; auto.
  Qed.

  Lemma csim_hml: p q,
    contrasimilar p qhml_equiv p q.
  Proof.
    split; intros.
    apply csim_hmlA; auto.
    apply csim_hmlE; auto.
  Qed.

  Lemma not_not: P,
    excluded_middle → (~~P P).
  Proof. intros; by_contradiction; intuition. Qed.

  Lemma not_exists: A P, excluded_middle → (¬ (a:A), P a) → a, ¬P a.
  Proof. intros; by_contradiction. apply H0. a. apply not_not; auto. Qed.

  Lemma not_forall: A (P:AProp),
    excluded_middle
    inhabited A
    (¬ a, P a) → a, ¬P a.
  Proof.
    intros; by_contradiction.
    apply H1; intros.
    by_contradiction. apply H2; eauto.
  Qed.

  Lemma not_impl: (P1 P2: Prop),
    excluded_middle
    ((~(P1P2)) (P1 ¬P2)).
  Proof. intros; by_contradiction; intuition. Qed.

  Lemma not_and: P1 P2,
    excluded_middle
    ((~(P1P2)) (¬P1 ¬P2)).
  Proof. intros; by_contradiction; intuition. Qed.

  Lemma not_or: P1 P2,
    excluded_middle
    ((~(P1P2)) (¬P1 ¬P2)).
  Proof. intros; by_contradiction; intuition. Qed.

  Lemma not_iff: P1 P2,
    excluded_middle
    ((~(P1P2)) ((P1¬P2) (P2¬P1))).
  Proof. intros; by_contradiction; intuition. Qed.

  Lemma hml_implA_neg: p q,
    excluded_middle
    ¬hml_implA p q f, forcesA p f ¬forcesA q f.
  Proof.
    intros.
    by_contradiction.
    apply H0.
    generalize (not_exists _ _ H H1); clear H1; intros H1.
    intro f; intros.
    specialize (H1 f).
    rewrite not_and in H1; auto.
    rewrite not_not in H1; auto.
    intuition.
  Qed.

  Lemma hml_implE_neg: p q,
    excluded_middle
    ¬hml_implE p q f, forcesE p f ¬forcesE q f.
  Proof.
    intros.
    by_contradiction.
    apply H0.
    generalize (not_exists _ _ H H1); clear H1; intros H1.
    intro f; intros.
    specialize (H1 f).
    rewrite not_and in H1; auto.
    rewrite not_not in H1; auto.
    intuition.
  Qed.

  Lemma exists_list_unsatA: p lq,
    excluded_middle
    ( q, In q lq¬hml_implA p q) →
     lf,
      ( f, In f lf q, In q lq forcesA p f ¬forcesA q f)
      ( q, In q lq f, In f lf forcesA p f ¬forcesA q f).
  Proof.
    induction lq; introv Hem; intros.
    × (@nil phiA); split; intros; inverts H0.
    × lapply (H a); intros.
    edestruct hml_implA_neg as [f[??]]; eauto.
    edestruct IHlq as [lf[??]]; eauto.
    intros. eapply H; right; auto.
     (f::lf); split; intros.
    destruct H5; subst.
     a; splits; auto. left; auto.
    edestruct H3 as [q[?[??]]]; eauto.
     q; splits; auto. right; auto.
    destruct H5; subst.
     f; splits; auto. left; auto.
    edestruct H4 as [f'[?[??]]]; eauto.
     f'; splits; auto. right; auto.
    left; auto.
  Qed.

  Lemma exists_list_unsatE: p lq,
    excluded_middle
    ( q, In q lq¬hml_implE q p) →
     lf,
      ( f, In f lf q, In q lq ¬forcesE p f forcesE q f)
      ( q, In q lq f, In f lf ¬forcesE p f forcesE q f).
  Proof.
    induction lq; introv Hem; intros.
    × (@nil phiE); split; intros; inverts H0.
    × lapply (H a); intros.
    edestruct hml_implE_neg as [f[??]]; eauto.
    edestruct IHlq as [lf[??]]; eauto.
    intros. eapply H; right; auto.
     (f::lf); split; intros.
    destruct H5; subst.
     a; splits; auto. left; auto.
    edestruct H3 as [q[?[??]]]; eauto.
     q; splits; auto. right; auto.
    destruct H5; subst.
     f; splits; auto. left; auto.
    edestruct H4 as [f'[?[??]]]; eauto.
     f'; splits; auto. right; auto.
    left; auto.
  Qed.

  Lemma hml_pcsim: p q,
    excluded_middle
    weakly_image_finite lts
    ( p, ¬is_halted p) →
    (hml_implE p q hml_implA q p) →
    partial_contrasimilar p q.
  Proof.
    introv Hem Hif Hnh ?.
     (fun p qhml_implE p q hml_implA q p).
    splits; auto; clear p q H; intros p q [?|?]; intros.
    × apply Hnh in H0; false.
    × apply Hnh in H0; false.
    × by_contradiction.
    assert ( q', step_star q la q'¬hml_implA p' q').
    { intros. apply not_exists with (a:=q') in H1; auto. }
    clear H1. rename H2 into H1.
    destruct (Hif la q) as [lq' ?].
    setoid_rewrite H2 in H1.
    edestruct exists_list_unsatA with (lq:=lq') as [lf[??]]; auto.

    assert (forcesE p (ext la (list_conjA lf))).
    { simpl. p'; split; auto.
      apply f_list_conjA.
      intros.
      destruct (H3 f) as [q'[?[??]]]; auto. }

    apply H in H5.
    destruct H5 as [q'[??]].
    edestruct (H4 q') as [f[?[??]]].
    apply H2; auto.
    rewrite f_list_conjA in H6.
    apply H6 in H7.
    contradiction.

    × by_contradiction.
    assert ( q', step_star q la q'¬hml_implE q' p').
    { intros. apply not_exists with (a:=q') in H1; auto. }
    clear H1. rename H2 into H1.
    destruct (Hif la q) as [lq' ?].
    setoid_rewrite H2 in H1.
    edestruct exists_list_unsatE with (lq:=lq') as [lf[??]]; auto.

    assert (forcesA q (all la (list_disjE lf))).
    { simpl. intros q' ?.
      apply f_list_disjE.
      edestruct (H4 q') as [f[?[??]]]; eauto. apply H2; auto. }

    apply H in H5.
    simpl in H5.
    apply H5 in H0.
    rewrite f_list_disjE in H0.
    destruct H0 as [f[??]].
    destruct (H3 f) as [q'[?[??]]]; auto.
  Qed.

  Lemma hml_csim: p q,
    excluded_middle
    weakly_image_finite lts
    ( p, ¬is_halted p) →
    (hml_implE p q hml_implA q p) →
    (hml_implE q p hml_implA p q) →
    contrasimilar p q.
  Proof.
    intros.
    apply pcsim_csim;
      apply hml_pcsim; auto.
  Qed.

  Lemma hmlE_csim: p q,
    excluded_middle
    weakly_image_finite lts
    ( p, ¬is_halted p) →
    hml_equivE p q
    contrasimilar p q.
  Proof.
    unfold hml_equivE; intros.
    apply hml_csim; intuition.
  Qed.

  Lemma hmlA_csim: p q,
    excluded_middle
    weakly_image_finite lts
    ( p, ¬is_halted p) →
    hml_equivA p q
    contrasimilar p q.
  Proof.
    unfold hml_equivA; intros.
    apply hml_csim; intuition.
  Qed.

  Corollary hmlA_hmlE: p q,
    excluded_middle
    weakly_image_finite lts
    ( p, ¬is_halted p) →
    (hml_equivA p q hml_equivE p q).
  Proof.
    split; intros.
    apply csim_hmlE.
    apply hmlA_csim; auto.
    apply csim_hmlA.
    apply hmlE_csim; auto.
  Qed.

End HML_DecoupledBisimulation.