Theory HML_SRBB

text ‹\newpage›
section ‹ Stability-Respecting Branching Bisimilarity (HML$_\text{SRBB}$) \label{sect:hmlSRBB} ›
theory HML_SRBB
  imports Main LTS_Semantics
begin
text ‹This section describes the largest subset of the full HML language in section \ref{sect:HML} that we are
using for purposes of silent step spectroscopy. It is supposed to characterize the most fine grained
behavioural equivalence that we may decide: Stability-Respecting Branching Bisimilarity (SRBB). While
there are good reasons to believe that this subset truly characterizes SRBB (c.f.\cite{bisping2023lineartimebranchingtime}),
we do not provide a formal proof. From this sublanguage smaller subsets are derived
via the notion of expressiveness prices (\ref{sect:ExpressivenessMeasure}). ›

text ‹
The mutually recursive data types @{term hml_srbb}, @{term hml_srbb_inner} and @{term hml_srbb_conjunct}
represent the subset of all @{term hml} formulas, which characterize stability-respecting branching
bisimilarity (abbreviated to 'SRBB').
\\\\
When a parameter is of type @{term hml_srbb} we typically use φ› as a name,
for type @{term hml_srbb_inner} we use χ› and for type @{term hml_srbb_conjunct} we use ψ›.

The data constructors are to be interpreted as follows:
\begin{itemize}
  \item in @{term hml_srbb}:
  \begin{itemize}
    \item @{term TT} encodes ⊤›
    \item (Internal χ)› encodes ⟨ε⟩χ›
    \item (ImmConj I ψs)› encodes $\bigwedge\nolimits_{i \in \mathrm{\texttt{I}}} {\psi s}(i)$
  \end{itemize}
  \item in @{term hml_srbb_inner}
  \begin{itemize}
    \item (Obs α φ)› encodes (α)φ› (Note the difference to \cite{bisping2023lineartimebranchingtime})
    \item (Conj I ψs)› encode $\bigwedge\nolimits_{i \in \mathrm{\texttt{I}}} {\psi s}(i)$
    \item (StableConj I ψs)› encodes $\neg\langle\tau\rangle\top \land \bigwedge\nolimits_{i \in \mathrm{\texttt{I}}} {\psi s}(i)$
    \item (BranchConj α φ I ψs)› encodes $(\alpha)\varphi \land \bigwedge\nolimits_{i \in \mathrm{\texttt{I}}} {\psi s}(i)$
  \end{itemize}
  \item in @{term hml_srbb_conjunct}
  \begin{itemize}
    \item (Pos χ)› encodes ⟨ε⟩χ›
    \item (Neg χ)› encodes ¬⟨ε⟩χ›
  \end{itemize}
\end{itemize}

For justifications regarding the explicit inclusion of @{term TT} and
the encoding of conjunctions via index sets @{term I} and mapping from indices to conjuncts @{term ψs},
reference the @{term TT} and @{term Conj} data constructors of the type @{term hml} in section \ref{sect:HML}.
›

datatype
  ('act, 'i) hml_srbb =
    TT |
    Internal ('act, 'i) hml_srbb_inner |
    ImmConj 'i set 'i  ('act, 'i) hml_srbb_conjunct
and
  ('act, 'i) hml_srbb_inner =
    Obs 'act ('act, 'i) hml_srbb |
    Conj 'i set 'i  ('act, 'i) hml_srbb_conjunct |
    StableConj 'i set 'i  ('act, 'i) hml_srbb_conjunct |
    BranchConj 'act ('act, 'i) hml_srbb
               'i set 'i  ('act, 'i) hml_srbb_conjunct
and
  ('act, 'i) hml_srbb_conjunct =
    Pos ('act, 'i) hml_srbb_inner |
    Neg ('act, 'i) hml_srbb_inner


subsection ‹ Semantics of HML$_\text{SRBB}$ Formulas ›

text ‹
This section describes how semantic meaning is assigned to HML$_\text{SRBB}$ formulas in the context of a LTS.
We define what it means for a process @{term p} to satisfy a HML$_\text{SRBB}$ formula @{term φ},
written as p ⊨SRBB φ›.
›

context LTS_Tau
begin

primrec
      hml_srbb_models :: 's  ('a, 's) hml_srbb  bool (infixl ⊨SRBB 60)
  and hml_srbb_inner_models :: 's  ('a, 's) hml_srbb_inner  bool
  and hml_srbb_conjunct_models :: 's  ('a, 's) hml_srbb_conjunct  bool where
  hml_srbb_models state TT =
    True |
  hml_srbb_models state (Internal χ) =
    (p'. state  p'  (hml_srbb_inner_models p' χ)) |
  hml_srbb_models state (ImmConj I ψs) =
    (iI. hml_srbb_conjunct_models state (ψs i)) |

  hml_srbb_inner_models state (Obs a φ) =
    ((p'. state  a p'  hml_srbb_models p' φ)  a = τ  hml_srbb_models state φ) |
  hml_srbb_inner_models state (Conj I ψs) =
    (iI. hml_srbb_conjunct_models state (ψs i)) |
  hml_srbb_inner_models state (StableConj I ψs) =
    ((p'. state  τ p')  (iI. hml_srbb_conjunct_models state (ψs i))) |
  hml_srbb_inner_models state (BranchConj a φ I ψs) =
    (((p'. state  a p'  hml_srbb_models p' φ)  a = τ  hml_srbb_models state φ)
     (iI. hml_srbb_conjunct_models state (ψs i))) |

  hml_srbb_conjunct_models state (Pos χ) =
    (p'. state  p'  hml_srbb_inner_models p' χ) |
  hml_srbb_conjunct_models state (Neg χ) =
    (p'. state  p'  hml_srbb_inner_models p' χ)

sublocale lts_semantics step hml_srbb_models .
sublocale hml_srbb_inner: lts_semantics where models = hml_srbb_inner_models .
sublocale hml_srbb_conj: lts_semantics where models = hml_srbb_conjunct_models .

subsection ‹ Different Variants of Verum ›

lemma empty_conj_trivial[simp]:
  state ⊨SRBB ImmConj {} ψs
  hml_srbb_inner_models state (Conj {} ψs)
  hml_srbb_inner_models state (Obs τ TT)
  by simp+

text ⋀{(τ)⊤}› is trivially true. ›
lemma empty_branch_conj_tau:
  hml_srbb_inner_models state (BranchConj τ TT {} ψs)
  by auto

lemma stable_conj_parts:
  assumes
    hml_srbb_inner_models p (StableConj I Ψ)
    i  I
  shows hml_srbb_conjunct_models p (Ψ i)
  using assms by auto

lemma branching_conj_parts:
  assumes
    hml_srbb_inner_models p (BranchConj α φ I Ψ)
    i  I
  shows hml_srbb_conjunct_models p (Ψ i)
  using assms by auto

lemma branching_conj_obs:
  assumes
    hml_srbb_inner_models p (BranchConj α φ I Ψ)
  shows hml_srbb_inner_models p (Obs α φ)
  using assms by auto

subsection ‹ Distinguishing Formulas ›

text ‹Now, we take a look at some basic properties of the distinguishes› predicate: ›

text ⊤› can never distinguish two processes. This is due to the fact that every process
satisfies T›. Therefore, the second part of the definition of distinguishes› never holds. ›
lemma verum_never_distinguishes:
  ¬ distinguishes TT p q
  by simp

text ‹
If $\bigwedge\nolimits_{i \in I} {\psi s}(i)$ distinguishes @{term p} from @{term q},
then there must be at least one conjunct in this conjunction that distinguishes @{term p} from @{term q}.
›
lemma srbb_dist_imm_conjunction_implies_dist_conjunct:
  assumes distinguishes (ImmConj I ψs) p q
  shows iI. hml_srbb_conj.distinguishes (ψs i) p q
  using assms by auto

text ‹
If there is one conjunct in that distinguishes @{term p} from @{term q}
and @{term p} satisfies all other conjuncts in a conjunction
then $\bigwedge\nolimits_{i \in I} {\psi s}(i)$ (where $\psi s$ ranges over the previously mentioned
conjunctions) distinguishes @{term p} from @{term q}.
›
lemma srbb_dist_conjunct_implies_dist_imm_conjunction:
  assumes iI
      and hml_srbb_conj.distinguishes (ψs i) p q
      and iI. hml_srbb_conjunct_models p (ψs i)
    shows distinguishes (ImmConj I ψs) p q
  using assms by auto

text ‹
If $\bigwedge\nolimits_{i \in I} {\psi s}(i)$ distinguishes @{term p} from @{term q},
then there must be at least one conjunct in this conjunction that distinguishes @{term p} from @{term q}.
›
lemma srbb_dist_conjunction_implies_dist_conjunct:
  assumes hml_srbb_inner.distinguishes (Conj I ψs) p q
  shows iI. hml_srbb_conj.distinguishes (ψs i) p q
  using assms by auto

text ‹
In the following, we replicate @{term srbb_dist_conjunct_implies_dist_imm_conjunction} for simple conjunctions
in @{term hml_srbb_inner}.
›
lemma srbb_dist_conjunct_implies_dist_conjunction:
  assumes iI
      and hml_srbb_conj.distinguishes (ψs i) p q
      and iI. hml_srbb_conjunct_models p (ψs i)
  shows hml_srbb_inner.distinguishes (Conj I ψs) p q
  using assms by auto

text ‹
We also replicate @{term srbb_dist_imm_conjunction_implies_dist_conjunct} for branching conjunctions
$(\alpha)\varphi\land\bigwedge\nolimits_{i \in I} {\psi s}(i)$.
Here, either the branching condition distinguishes @{term p} from @{term q} or there must be
a distinguishing conjunct.
›
lemma srbb_dist_branch_conjunction_implies_dist_conjunct_or_branch:
  assumes hml_srbb_inner.distinguishes (BranchConj α φ I ψs) p q
  shows (iI. hml_srbb_conj.distinguishes (ψs i) p q)
        (hml_srbb_inner.distinguishes (Obs α φ) p q)
  using assms by force

text ‹
In the following, we replicate @{term srbb_dist_conjunct_implies_dist_imm_conjunction} for branching conjunctions
in @{term hml_srbb_inner}.
›
lemma srbb_dist_conjunct_or_branch_implies_dist_branch_conjunction:
  assumes i  I. hml_srbb_conjunct_models p (ψs i)
      and hml_srbb_inner_models p (Obs α φ)
      and (iI  hml_srbb_conj.distinguishes (ψs i) p q)
          (hml_srbb_inner.distinguishes (Obs α φ) p q)
  shows hml_srbb_inner.distinguishes (BranchConj α φ I ψs) p q
  using assms by force

subsection ‹ HML$_\text{SRBB}$ Implication ›

abbreviation hml_srbb_impl
  :: ('a, 's) hml_srbb  ('a, 's) hml_srbb  bool  (infixr  70)
where
  hml_srbb_impl  entails

abbreviation
  hml_srbb_impl_inner
  :: ('a, 's) hml_srbb_inner  ('a, 's) hml_srbb_inner  bool
  (infix χ⇛ 70)
where
  (χ⇛)  hml_srbb_inner.entails

abbreviation
  hml_srbb_impl_conjunct
  :: ('a, 's) hml_srbb_conjunct  ('a, 's) hml_srbb_conjunct  bool
  (infix ψ⇛ 70)
where
  (ψ⇛)  hml_srbb_conj.entails

subsection ‹ HML$_\text{SRBB}$ Equivalence ›

text ‹
We define HML$_\text{SRBB}$ formula equivalence to by appealing to HML$_\text{SRBB}$ implication.
A HML$_\text{SRBB}$ formula is equivalent to another formula if both imply each other.
›

abbreviation
  hml_srbb_eq
  :: ('a, 's) hml_srbb  ('a, 's) hml_srbb  bool
  (infix ⇚srbb⇛ 70)
where
  (⇚srbb⇛)  logical_eq

abbreviation
  hml_srbb_eq_inner
  :: ('a, 's) hml_srbb_inner  ('a, 's) hml_srbb_inner  bool
  (infix ⇚χ⇛ 70)
where
  (⇚χ⇛)  hml_srbb_inner.logical_eq

abbreviation
  hml_srbb_eq_conjunct
  :: ('a, 's) hml_srbb_conjunct  ('a, 's) hml_srbb_conjunct  bool
  (infix ⇚ψ⇛ 70)
  where
  (⇚ψ⇛)  hml_srbb_conj.logical_eq

subsection ‹ Substitution ›

lemma srbb_internal_subst:
  assumes χl ⇚χ⇛ χr
      and φ ⇚srbb⇛ (Internal χl)
    shows φ ⇚srbb⇛ (Internal χr)
  using assms by force

subsection ‹ Congruence ›

text ‹ This section provides means to derive new equivalences by extending both sides with a given prefix.  ›

text ‹ Prepending $\langle\varepsilon\rangle\dots$ preserves equivalence. ›
lemma internal_srbb_cong:
  assumes χl ⇚χ⇛ χr
  shows (Internal χl) ⇚srbb⇛ (Internal χr)
  using assms by auto

text ‹If equivalent conjuncts are included in an otherwise identical conjunction, the equivalence is preserved.  ›
lemma immconj_cong:
  assumes ψsl ` I = ψsr ` I
      and ψsl s ⇚ψ⇛ ψsr s
  shows ImmConj (I  {s}) ψsl ⇚srbb⇛ ImmConj (I  {s}) ψsr
  using assms
  by (auto) (metis (mono_tags, lifting) image_iff)+

text ‹ Prepending $(\alpha)\dots$ preserves equivalence. ›
lemma obs_srbb_cong:
  assumes φl ⇚srbb⇛ φr
  shows (Obs α φl) ⇚χ⇛ (Obs α φr)
  using assms by auto

subsection ‹ Known Equivalence Elements ›

text ‹The formula $(\tau)\top$ is equivalent to $\bigwedge\{\}$. ›
lemma srbb_obs_τ_is_χTT: Obs τ TT ⇚χ⇛ Conj {} ψs
  by simp

text ‹The formula $(\alpha)\varphi$ is equivalent to $(\alpha)\varphi \land \bigwedge\{\}$. ›
lemma srbb_obs_is_empty_branch_conj: Obs α φ ⇚χ⇛ BranchConj α φ {} ψs
  by auto

text ‹ The formula $\top$ is equivalent to $\langle\varepsilon\rangle\bigwedge\{\}$.›
lemma srbb_TT_is_χTT: TT ⇚srbb⇛ Internal (Conj {} ψs)
  using LTS_Tau.refl by force

text ‹ The formula $\top$ is equivalent to $\bigwedge\{\}$.›
lemma srbb_TT_is_empty_conj: TT ⇚srbb⇛ ImmConj {} ψs
  by simp

text ‹Positive conjuncts in stable conjunctions can be replaced by negative ones.›
lemma srbb_stable_Neg_normalizable:
  assumes
    i  I Ψ i = Pos χ
    Ψ' = Ψ(i:= Neg (StableConj {left} (λ_. Neg χ)))
  shows
    Internal (StableConj I Ψ) ⇚srbb⇛ Internal (StableConj I Ψ')
proof (rule logical_eqI)
  fix p
  assume p ⊨SRBB Internal (StableConj I Ψ)
  then obtain p' where p'_spec: p  p' hml_srbb_inner_models p' (StableConj I Ψ) by auto
  hence stable_state p' by auto
  from p'_spec have p''. p'  p''  hml_srbb_inner_models p'' χ
    using assms(1,2) by auto
  with stable_state p' have hml_srbb_inner_models p' χ
    using stable_state_stable by blast
  hence hml_srbb_conjunct_models p' (Neg (StableConj {left} (λ_. Neg χ)))
    using stable_state p' stable_state_stable by (auto, blast)
  hence hml_srbb_inner_models p' (StableConj I Ψ')
    unfolding assms(3) using p'_spec by auto
  thus p ⊨SRBB hml_srbb.Internal (StableConj I Ψ')
    using p  p' by auto
next
  fix p
  assume p ⊨SRBB Internal (StableConj I Ψ')
  then obtain p' where p'_spec: p  p' hml_srbb_inner_models p' (StableConj I Ψ') by auto
  hence stable_state p' by auto
  from p'_spec(2) have other_conjuncts: jI. i  j  hml_srbb_conjunct_models p' (Ψ j)
    using assms stable_conj_parts fun_upd_apply by metis
  from p'_spec(2) have hml_srbb_conjunct_models p' (Ψ' i)
    using assms(1) stable_conj_parts by blast
  hence hml_srbb_conjunct_models p' (Neg (StableConj {left} (λ_. Neg χ)))
    unfolding assms(3) by auto
  with stable_state p' have hml_srbb_inner_models p' χ
    using stable_state_stable by (auto, metis silent_reachable.simps)
  then have hml_srbb_conjunct_models p' (Pos χ)
    using LTS_Tau.refl by fastforce
  hence hml_srbb_inner_models p' (StableConj I Ψ)
    using p'_spec assms other_conjuncts by auto
  thus p ⊨SRBB hml_srbb.Internal (StableConj I Ψ)
    using p'_spec(1) by auto
qed

text ‹All positive conjuncts in stable conjunctions can be replaced by negative ones at once.›
lemma srbb_stable_Neg_normalizable_set:
  assumes
    Ψ' = (λi. case (Ψ i) of
      Pos χ  Neg (StableConj {left} (λ_. Neg χ)) |
      Neg χ  Neg χ)
  shows
    Internal (StableConj I Ψ) ⇚srbb⇛ Internal (StableConj I Ψ')
proof (rule logical_eqI)
  fix p
  assume p ⊨SRBB Internal (StableConj I Ψ)
  then obtain p' where p'_spec: p  p' hml_srbb_inner_models p' (StableConj I Ψ) by auto
  hence stable_state p' by auto
  from p'_spec have
    χ i. iI  Ψ i = Pos χ  (p''. p'  p''  hml_srbb_inner_models p'' χ)
    by fastforce
  with stable_state p' have χ i. iI  Ψ i = Pos χ  hml_srbb_inner_models p' χ
    using stable_state_stable by blast
  hence pos_rewrite: χ i. iI  Ψ i = Pos χ 
      hml_srbb_conjunct_models p' (Neg (StableConj {left} (λ_. Neg χ)))
    using stable_state p' stable_state_stable by (auto, blast)
  hence hml_srbb_inner_models p' (StableConj I Ψ')
    unfolding assms using p'_spec
    by (auto, metis (no_types, lifting) hml_srbb_conjunct.exhaust hml_srbb_conjunct.simps(5,6)
        pos_rewrite)
  thus p ⊨SRBB Internal (StableConj I Ψ')
    using p  p' by auto
next
  fix p
  assume p ⊨SRBB Internal (StableConj I Ψ')
  then obtain p' where p'_spec: p  p' hml_srbb_inner_models p' (StableConj I Ψ') by auto
  hence stable_state p' by auto
  from p'_spec(2) have other_conjuncts:
      χ i. iI  Ψ i = Neg χ  hml_srbb_conjunct_models p' (Ψ i)
    using assms stable_conj_parts by (metis hml_srbb_conjunct.simps(6))
  from p'_spec(2) have χ i. iI  Ψ i = Pos χ  hml_srbb_conjunct_models p' (Ψ' i)
    using assms(1) stable_conj_parts by blast
  hence χ i. iI  Ψ i = Pos χ 
      hml_srbb_conjunct_models p' (Neg (StableConj {left} (λ_. Neg χ)))
    unfolding assms by auto
  with stable_state p' have χ i. iI  Ψ i = Pos χ  hml_srbb_inner_models p' χ
    using stable_state_stable by (auto, metis silent_reachable.simps)
  then have pos_conjuncts:
      χ i. iI  Ψ i = Pos χ hml_srbb_conjunct_models p' (Pos χ)
    using hml_srbb_conjunct_models.simps(1) silent_reachable.simps by blast
  hence hml_srbb_inner_models p' (StableConj I Ψ)
    using p'_spec assms other_conjuncts
    by (auto, metis other_conjuncts pos_conjuncts hml_srbb_conjunct.exhaust)
  thus p ⊨SRBB Internal (StableConj I Ψ)
    using p'_spec(1) by auto
qed

definition conjunctify_distinctions ::
  ('s  ('a, 's) hml_srbb)  's  ('s  ('a, 's) hml_srbb_conjunct) where
  conjunctify_distinctions Φ p  λq.
    case (Φ q) of
      TT  undefined
    | Internal χ  Pos χ
    | ImmConj I Ψ  Ψ (SOME i. iI  hml_srbb_conj.distinguishes (Ψ i) p q)

lemma distinction_conjunctification:
  assumes
    qI. distinguishes (Φ q) p q
  shows
    qI. hml_srbb_conj.distinguishes ((conjunctify_distinctions Φ p) q) p q
  unfolding conjunctify_distinctions_def
proof
  fix q
  assume q_I: qI
  show hml_srbb_conj.distinguishes
          (case Φ q of hml_srbb.Internal x  hml_srbb_conjunct.Pos x
           | ImmConj I Ψ  Ψ (SOME i. i  I  hml_srbb_conj.distinguishes (Ψ i) p q))
          p q
  proof (cases Φ q)
    case TT
    then show ?thesis using assms q_I by fastforce
  next
    case (Internal χ)
    then show ?thesis using assms q_I by auto
  next
    case (ImmConj J Ψ)
    then have i  J. hml_srbb_conj.distinguishes (Ψ i) p q
      using assms q_I by auto
    then show ?thesis
      by (metis (mono_tags, lifting) ImmConj hml_srbb.simps(11) someI)
  qed
qed

lemma distinction_combination:
  fixes p q
  defines   {q'. q  q'  (φ. distinguishes φ p q')}
  assumes
    p ↦a α p'
    q' .
      q''. q' ↦a α q''  (distinguishes (Φ q'') p' q'')
  shows
    q'.
      hml_srbb_inner.distinguishes (Obs α (ImmConj {q''. q'''. q''' ↦a α q''}
                                                   (conjunctify_distinctions Φ p'))) p q'
proof -
  have q' . q''{q''. q' ↦a α q''}.
      hml_srbb_conj.distinguishes ((conjunctify_distinctions Φ p') q'') p' q''
  proof clarify
    fix q' q''
    assume q'   q' ↦a α q''
    thus hml_srbb_conj.distinguishes (conjunctify_distinctions Φ p' q'') p' q''
      using distinction_conjunctification assms(3)
      by (metis mem_Collect_eq)
  qed
  hence q' . q''{q''. q1'. q1' ↦a α q''}.
      hml_srbb_conj.distinguishes ((conjunctify_distinctions Φ p') q'') p' q'' by blast
  hence q' . q''. q' ↦a α q''
     distinguishes (ImmConj {q''. q1'. q1' ↦a α q''}
                               (conjunctify_distinctions Φ p')) p' q'' by auto
  thus q'.
      hml_srbb_inner.distinguishes (Obs α (ImmConj {q''. q'''. q''' ↦a α q''}
                                                   (conjunctify_distinctions Φ p'))) p q'
    by (auto) (metis assms(2))+
qed

definition conjunctify_distinctions_dual ::
  ('s  ('a, 's) hml_srbb)  's  ('s  ('a, 's) hml_srbb_conjunct) where
  conjunctify_distinctions_dual Φ p  λq.
    case (Φ q) of
      TT  undefined
    | Internal χ  Neg χ
    | ImmConj I Ψ 
      (case Ψ (SOME i. iI  hml_srbb_conj.distinguishes (Ψ i) q p) of
        Pos χ  Neg χ | Neg χ  Pos χ)

lemma dual_conjunct:
  assumes
    hml_srbb_conj.distinguishes ψ p q
  shows
    hml_srbb_conj.distinguishes (case ψ of
               hml_srbb_conjunct.Pos χ  hml_srbb_conjunct.Neg χ
               | hml_srbb_conjunct.Neg χ  hml_srbb_conjunct.Pos χ) q p
  using assms
  by (cases ψ, auto)

lemma distinction_conjunctification_dual:
  assumes
    qI. distinguishes (Φ q) q p
  shows
    qI. hml_srbb_conj.distinguishes (conjunctify_distinctions_dual Φ p q) p q
  unfolding conjunctify_distinctions_dual_def
proof
  fix q
  assume q_I: qI
  show hml_srbb_conj.distinguishes
          (case Φ q of hml_srbb.Internal x  hml_srbb_conjunct.Neg x
           | ImmConj I Ψ 
               ( case Ψ (SOME i. i  I  hml_srbb_conj.distinguishes (Ψ i) q p) of
                  hml_srbb_conjunct.Pos x  hml_srbb_conjunct.Neg x
               | hml_srbb_conjunct.Neg x  hml_srbb_conjunct.Pos x))
          p q
  proof (cases Φ q)
    case TT
    then show ?thesis using assms q_I by fastforce
  next
    case (Internal χ)
    then show ?thesis using assms q_I by auto
  next
    case (ImmConj J Ψ)
    then have i  J. hml_srbb_conj.distinguishes (Ψ i) q p
      using assms q_I by auto
    hence hml_srbb_conj.distinguishes (case Ψ
      (SOME i. i  J  hml_srbb_conj.distinguishes (Ψ i) q p) of
               hml_srbb_conjunct.Pos x  hml_srbb_conjunct.Neg x
               | hml_srbb_conjunct.Neg x  hml_srbb_conjunct.Pos x) p q
      by (metis (no_types, lifting) dual_conjunct someI_ex)
    then show ?thesis unfolding ImmConj by auto
  qed
qed

lemma distinction_conjunctification_two_way:
  assumes
    qI. distinguishes (Φ q) p q  distinguishes (Φ q) q p
  shows
    qI. hml_srbb_conj.distinguishes ((if distinguishes (Φ q) p q then conjunctify_distinctions else conjunctify_distinctions_dual) Φ p q) p q
proof safe
  fix q
  assume q  I
  then consider distinguishes (Φ q) p q | distinguishes (Φ q) q p using assms by blast
  thus hml_srbb_conj.distinguishes ((if distinguishes (Φ q) p q then conjunctify_distinctions else conjunctify_distinctions_dual) Φ p q) p q
  proof cases
    case 1
    then show ?thesis using distinction_conjunctification
      by (smt (verit) singleton_iff)
  next
    case 2
    then show ?thesis using distinction_conjunctification_dual singleton_iff
      unfolding distinguishes_def
      by (smt (verit, ccfv_threshold))
  qed
qed

end (* LTS_Tau *)

end