Theory Propositional_Wff

section ‹Propositional Well-Formed Formulas›

theory Propositional_Wff
  imports
    Syntax
    Boolean_Algebra
begin

subsection ‹Syntax›

inductive_set pwffs :: "form set" where
  T_pwff: "To  pwffs"
| F_pwff: "Fo  pwffs"
| var_pwff: "po pwffs"
| neg_pwff: "𝒬 A  pwffs" if "A  pwffs"
| conj_pwff: "A 𝒬 B  pwffs" if "A  pwffs" and "B  pwffs"
| disj_pwff: "A 𝒬 B  pwffs" if "A  pwffs" and "B  pwffs"
| imp_pwff: "A 𝒬 B  pwffs" if "A  pwffs" and "B  pwffs"
| eqv_pwff: "A 𝒬 B  pwffs" if "A  pwffs" and "B  pwffs"

lemmas [intro!] = pwffs.intros

lemma pwffs_distinctnesses [induct_simp]:
  shows "To  Fo"
  and "To  po⇙"
  and "To  𝒬 A"
  and "To  A 𝒬 B"
  and "To  A 𝒬 B"
  and "To  A 𝒬 B"
  and "To  A 𝒬 B"
  and "Fo  po⇙"
  and "Fo  𝒬 A"
  and "Fo  A 𝒬 B"
  and "Fo  A 𝒬 B"
  and "Fo  A 𝒬 B"
  and "Fo  A 𝒬 B"
  and "po 𝒬 A"
  and "po A 𝒬 B"
  and "po A 𝒬 B"
  and "po A 𝒬 B"
  and "po A 𝒬 B"
  and "𝒬 A  B 𝒬 C"
  and "𝒬 A  B 𝒬 C"
  and "𝒬 A  B 𝒬 C"
  and "¬ (B = Fo  A = C)  𝒬 A  B 𝒬 C" ― ‹term𝒬 A is the same as term‹Fo 𝒬 A
  and "A 𝒬 B  C 𝒬 D"
  and "A 𝒬 B  C 𝒬 D"
  and "A 𝒬 B  C 𝒬 D"
  and "A 𝒬 B  C 𝒬 D"
  and "A 𝒬 B  C 𝒬 D"
  and "A 𝒬 B  C 𝒬 D"
  by simp_all

lemma pwffs_injectivities [induct_simp]:
  shows "𝒬 A = 𝒬 A'  A = A'"
  and "A 𝒬 B = A' 𝒬 B'  A = A'  B = B'"
  and "A 𝒬 B = A' 𝒬 B'  A = A'  B = B'"
  and "A 𝒬 B = A' 𝒬 B'  A = A'  B = B'"
  and "A 𝒬 B = A' 𝒬 B'  A = A'  B = B'"
  by simp_all

lemma pwff_from_neg_pwff [elim!]:
  assumes "𝒬 A  pwffs"
  shows "A  pwffs"
  using assms by cases simp_all

lemma pwffs_from_conj_pwff [elim!]:
  assumes "A 𝒬 B  pwffs"
  shows "{A, B}  pwffs"
  using assms by cases simp_all

lemma pwffs_from_disj_pwff [elim!]:
  assumes "A 𝒬 B  pwffs"
  shows "{A, B}  pwffs"
  using assms by cases simp_all

lemma pwffs_from_imp_pwff [elim!]:
  assumes "A 𝒬 B  pwffs"
  shows "{A, B}  pwffs"
  using assms by cases simp_all

lemma pwffs_from_eqv_pwff [elim!]:
  assumes "A 𝒬 B  pwffs"
  shows "{A, B}  pwffs"
  using assms by cases (simp_all, use F_pwff in fastforce)

lemma pwffs_subset_of_wffso:
  shows "pwffs  wffs⇘o⇙"
proof
  fix A
  assume "A  pwffs"
  then show "A  wffs⇘o⇙"
    by induction auto
qed

lemma pwff_free_vars_simps [simp]:
  shows T_fv: "free_vars To = {}"
  and F_fv: "free_vars Fo = {}"
  and var_fv: "free_vars (po) = {(p, o)}"
  and neg_fv: "free_vars (𝒬 A) = free_vars A"
  and conj_fv: "free_vars (A 𝒬 B) = free_vars A  free_vars B"
  and disj_fv: "free_vars (A 𝒬 B) = free_vars A  free_vars B"
  and imp_fv: "free_vars (A 𝒬 B) = free_vars A  free_vars B"
  and eqv_fv: "free_vars (A 𝒬 B) = free_vars A  free_vars B"
  by force+

lemma pwffs_free_vars_are_propositional:
  assumes "A  pwffs"
  and "v  free_vars A"
  obtains p where "v = (p, o)"
using assms by (induction A arbitrary: thesis) auto

lemma is_free_for_in_pwff [intro]:
  assumes "A  pwffs"
  and "v  free_vars A"
  shows "is_free_for B v A"
using assms proof (induction A)
  case (neg_pwff C)
  then show ?case
    using is_free_for_in_neg by simp
next
  case (conj_pwff C D)
  from conj_pwff.prems consider
    (a) "v  free_vars C" and "v  free_vars D"
  | (b) "v  free_vars C" and "v  free_vars D"
  | (c) "v  free_vars C" and "v  free_vars D"
    by auto
  then show ?case
  proof cases
    case a
    then show ?thesis
      using conj_pwff.IH by (intro is_free_for_in_conj)
  next
    case b
    have "is_free_for B v C"
      by (fact conj_pwff.IH(1)[OF b(1)])
    moreover from b(2) have "is_free_for B v D"
      using is_free_at_in_free_vars by blast
    ultimately show ?thesis
      by (rule is_free_for_in_conj)
  next
    case c
    from c(1) have "is_free_for B v C"
      using is_free_at_in_free_vars by blast
    moreover have "is_free_for B v D"
      by (fact conj_pwff.IH(2)[OF c(2)])
    ultimately show ?thesis
      by (rule is_free_for_in_conj)
  qed
next
  case (disj_pwff C D)
  from disj_pwff.prems consider
    (a) "v  free_vars C" and "v  free_vars D"
  | (b) "v  free_vars C" and "v  free_vars D"
  | (c) "v  free_vars C" and "v  free_vars D"
    by auto
  then show ?case
  proof cases
    case a
    then show ?thesis
      using disj_pwff.IH by (intro is_free_for_in_disj)
  next
    case b
    have "is_free_for B v C"
      by (fact disj_pwff.IH(1)[OF b(1)])
    moreover from b(2) have "is_free_for B v D"
      using is_free_at_in_free_vars by blast
    ultimately show ?thesis
      by (rule is_free_for_in_disj)
  next
    case c
    from c(1) have "is_free_for B v C"
      using is_free_at_in_free_vars by blast
    moreover have "is_free_for B v D"
      by (fact disj_pwff.IH(2)[OF c(2)])
    ultimately show ?thesis
      by (rule is_free_for_in_disj)
  qed
next
  case (imp_pwff C D)
  from imp_pwff.prems consider
    (a) "v  free_vars C" and "v  free_vars D"
  | (b) "v  free_vars C" and "v  free_vars D"
  | (c) "v  free_vars C" and "v  free_vars D"
    by auto
  then show ?case
  proof cases
    case a
    then show ?thesis
      using imp_pwff.IH by (intro is_free_for_in_imp)
  next
    case b
    have "is_free_for B v C"
      by (fact imp_pwff.IH(1)[OF b(1)])
    moreover from b(2) have "is_free_for B v D"
      using is_free_at_in_free_vars by blast
    ultimately show ?thesis
      by (rule is_free_for_in_imp)
  next
    case c
    from c(1) have "is_free_for B v C"
      using is_free_at_in_free_vars by blast
    moreover have "is_free_for B v D"
      by (fact imp_pwff.IH(2)[OF c(2)])
    ultimately show ?thesis
      by (rule is_free_for_in_imp)
  qed
next
  case (eqv_pwff C D)
  from eqv_pwff.prems consider
    (a) "v  free_vars C" and "v  free_vars D"
  | (b) "v  free_vars C" and "v  free_vars D"
  | (c) "v  free_vars C" and "v  free_vars D"
    by auto
  then show ?case
  proof cases
    case a
    then show ?thesis
      using eqv_pwff.IH by (intro is_free_for_in_equivalence)
  next
    case b
    have "is_free_for B v C"
      by (fact eqv_pwff.IH(1)[OF b(1)])
    moreover from b(2) have "is_free_for B v D"
      using is_free_at_in_free_vars by blast
    ultimately show ?thesis
      by (rule is_free_for_in_equivalence)
  next
    case c
    from c(1) have "is_free_for B v C"
      using is_free_at_in_free_vars by blast
    moreover have "is_free_for B v D"
      by (fact eqv_pwff.IH(2)[OF c(2)])
    ultimately show ?thesis
      by (rule is_free_for_in_equivalence)
  qed
qed auto

subsection ‹Semantics›

text ‹Assignment of truth values to propositional variables:›

definition is_tv_assignment :: "(nat  V)  bool" where
  [iff]: "is_tv_assignment φ  (p. φ p  elts 𝔹)"

text ‹Denotation of a pwff:›

definition is_pwff_denotation_function where
  [iff]: "is_pwff_denotation_function 𝒱 
    (
      φ. is_tv_assignment φ 
      (
        𝒱 φ To = T 
        𝒱 φ Fo = F 
        (p. 𝒱 φ (po) = φ p) 
        (A. A  pwffs  𝒱 φ (𝒬 A) =  𝒱 φ A) 
        (A B. A  pwffs  B  pwffs  𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B) 
        (A B. A  pwffs  B  pwffs  𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B) 
        (A B. A  pwffs  B  pwffs  𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B) 
        (A B. A  pwffs  B  pwffs  𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B)
      )
    )"

lemma pwff_denotation_is_truth_value:
  assumes "A  pwffs"
  and "is_tv_assignment φ"
  and "is_pwff_denotation_function 𝒱"
  shows "𝒱 φ A  elts 𝔹"
using assms(1) proof induction
  case (neg_pwff A)
  then have "𝒱 φ (𝒬 A) =  𝒱 φ A"
    using assms(2,3) by auto
  then show ?case
    using neg_pwff.IH by auto
next
  case (conj_pwff A B)
  then have "𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B"
    using assms(2,3) by auto
  then show ?case
    using conj_pwff.IH by auto
next
  case (disj_pwff A B)
  then have "𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B"
    using assms(2,3) by auto
  then show ?case
    using disj_pwff.IH by auto
next
  case (imp_pwff A B)
  then have "𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B"
    using assms(2,3) by blast
  then show ?case
    using imp_pwff.IH by auto
next
  case (eqv_pwff A B)
  then have "𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B"
    using assms(2,3) by blast
  then show ?case
    using eqv_pwff.IH by auto
qed (use assms(2,3) in auto)

lemma closed_pwff_is_meaningful_regardless_of_assignment:
  assumes "A  pwffs"
  and "free_vars A = {}"
  and "is_tv_assignment φ"
  and "is_tv_assignment ψ"
  and "is_pwff_denotation_function 𝒱"
  shows "𝒱 φ A = 𝒱 ψ A"
using assms(1,2) proof induction
  case T_pwff
  have "𝒱 φ To = T"
    using assms(3,5) by blast
  also have " = 𝒱 ψ To"
    using assms(4,5) by force
  finally show ?case .
next
  case F_pwff
  have "𝒱 φ Fo = F"
    using assms(3,5) by blast
  also have " = 𝒱 ψ Fo"
    using assms(4,5) by force
  finally show ?case .
next
  case (var_pwff p) ― ‹impossible case›
  then show ?case
    by simp
next
  case (neg_pwff A)
  from free_vars (𝒬 A) = {} have "free_vars A = {}"
    by simp
  have "𝒱 φ (𝒬 A) =  𝒱 φ A"
    using assms(3,5) and neg_pwff.hyps by auto
  also from free_vars A = {} have " =  𝒱 ψ A"
    using assms(3-5) and neg_pwff.IH by presburger
  also have " = 𝒱 ψ (𝒬 A)"
    using assms(4,5) and neg_pwff.hyps by simp
  finally show ?case .
next
  case (conj_pwff A B)
  from free_vars (A 𝒬 B) = {} have "free_vars A = {}" and "free_vars B = {}"
    by simp_all
  have "𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B"
    using assms(3,5) and conj_pwff.hyps(1,2) by auto
  also from free_vars A = {} and free_vars B = {} have " = 𝒱 ψ A  𝒱 ψ B"
    using conj_pwff.IH(1,2) by presburger
  also have " = 𝒱 ψ (A 𝒬 B)"
    using assms(4,5) and conj_pwff.hyps(1,2) by fastforce
  finally show ?case .
next
  case (disj_pwff A B)
  from free_vars (A 𝒬 B) = {} have "free_vars A = {}" and "free_vars B = {}"
    by simp_all
  have "𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B"
    using assms(3,5) and disj_pwff.hyps(1,2) by auto
  also from free_vars A = {} and free_vars B = {} have " = 𝒱 ψ A  𝒱 ψ B"
    using disj_pwff.IH(1,2) by presburger
  also have " = 𝒱 ψ (A 𝒬 B)"
    using assms(4,5) and disj_pwff.hyps(1,2) by fastforce
  finally show ?case .
next
  case (imp_pwff A B)
  from free_vars (A 𝒬 B) = {} have "free_vars A = {}" and "free_vars B = {}"
    by simp_all
  have "𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B"
    using assms(3,5) and imp_pwff.hyps(1,2) by auto
  also from free_vars A = {} and free_vars B = {} have " = 𝒱 ψ A  𝒱 ψ B"
    using imp_pwff.IH(1,2) by presburger
  also have " = 𝒱 ψ (A 𝒬 B)"
    using assms(4,5) and imp_pwff.hyps(1,2) by fastforce
  finally show ?case .
next
  case (eqv_pwff A B)
  from free_vars (A 𝒬 B) = {} have "free_vars A = {}" and "free_vars B = {}"
    by simp_all
  have "𝒱 φ (A 𝒬 B) = 𝒱 φ A  𝒱 φ B"
    using assms(3,5) and eqv_pwff.hyps(1,2) by auto
  also from free_vars A = {} and free_vars B = {} have " = 𝒱 ψ A  𝒱 ψ B"
    using eqv_pwff.IH(1,2) by presburger
  also have " = 𝒱 ψ (A 𝒬 B)"
    using assms(4,5) and eqv_pwff.hyps(1,2) by fastforce
  finally show ?case .
qed

inductive 𝒱B_graph for φ where
  𝒱B_graph_T: "𝒱B_graph φ To T"
| 𝒱B_graph_F: "𝒱B_graph φ Fo F"
| 𝒱B_graph_var: "𝒱B_graph φ (po) (φ p)"
| 𝒱B_graph_neg: "𝒱B_graph φ (𝒬 A) ( bA)" if "𝒱B_graph φ A bA"
| 𝒱B_graph_conj: "𝒱B_graph φ (A 𝒬 B) (bA  bB)" if "𝒱B_graph φ A bA" and "𝒱B_graph φ B bB"
| 𝒱B_graph_disj: "𝒱B_graph φ (A 𝒬 B) (bA  bB)" if "𝒱B_graph φ A bA" and "𝒱B_graph φ B bB"
| 𝒱B_graph_imp: "𝒱B_graph φ (A 𝒬 B) (bA  bB)" if "𝒱B_graph φ A bA" and "𝒱B_graph φ B bB"
| 𝒱B_graph_eqv: "𝒱B_graph φ (A 𝒬 B) (bA  bB)" if "𝒱B_graph φ A bA" and "𝒱B_graph φ B bB" and "A  Fo"

lemmas [intro!] = 𝒱B_graph.intros

lemma 𝒱B_graph_denotation_is_truth_value [elim!]:
  assumes "𝒱B_graph φ A b"
  and "is_tv_assignment φ"
  shows "b  elts 𝔹"
using assms proof induction
  case (𝒱B_graph_neg A bA)
  show ?case
    using 𝒱B_graph_neg.IH[OF assms(2)] by force
next
  case (𝒱B_graph_conj A bA B bB)
  then show ?case
    using 𝒱B_graph_conj.IH and assms(2) by force
next
  case (𝒱B_graph_disj A bA B bB)
  then show ?case
    using 𝒱B_graph_disj.IH and assms(2) by force
next
  case (𝒱B_graph_imp A bA B bB)
  then show ?case
    using 𝒱B_graph_imp.IH and assms(2) by force
next
  case (𝒱B_graph_eqv A bA B bB)
  then show ?case
    using 𝒱B_graph_eqv.IH and assms(2) by force
qed simp_all

lemma 𝒱B_graph_denotation_uniqueness:
  assumes "A  pwffs"
  and "is_tv_assignment φ"
  and "𝒱B_graph φ A b" and "𝒱B_graph φ A b'"
  shows "b = b'"
using assms(3,1,4) proof (induction arbitrary: b')
  case 𝒱B_graph_T
  from 𝒱B_graph φ To b' show ?case
    by (cases rule: 𝒱B_graph.cases) simp_all
next
  case 𝒱B_graph_F
  from 𝒱B_graph φ Fo b' show ?case
    by (cases rule: 𝒱B_graph.cases) simp_all
next
  case (𝒱B_graph_var p)
  from 𝒱B_graph φ (po) b' show ?case
    by (cases rule: 𝒱B_graph.cases) simp_all
next
  case (𝒱B_graph_neg A bA)
  with 𝒱B_graph φ (𝒬 A) b' have "𝒱B_graph φ A ( b')"
  proof (cases rule: 𝒱B_graph.cases)
    case (𝒱B_graph_neg A' bA)
    from 𝒬 A = 𝒬 A' have "A = A'"
      by simp
    with 𝒱B_graph φ A' bA have "𝒱B_graph φ A bA"
      by simp
    moreover have "bA =  b'"
    proof -
      have "bA  elts 𝔹"
        by (fact 𝒱B_graph_denotation_is_truth_value[OF 𝒱B_graph_neg(3) assms(2)])
      moreover from bA  elts 𝔹 and 𝒱B_graph_neg(2) have " b'  elts 𝔹"
        by fastforce
      ultimately show ?thesis
        using 𝒱B_graph_neg(2) by fastforce
    qed
    ultimately show ?thesis
      by blast
  qed simp_all
  moreover from 𝒱B_graph_neg.prems(1) have "A  pwffs"
    by (force elim: pwffs.cases)
  moreover have "bA  elts 𝔹" and "b'  elts 𝔹" and "bA =  b'"
  proof -
    show "bA  elts 𝔹"
      by (fact 𝒱B_graph_denotation_is_truth_value[OF 𝒱B_graph φ A bA assms(2)])
    show "b'  elts 𝔹"
      by (fact 𝒱B_graph_denotation_is_truth_value[OF 𝒱B_graph φ (𝒬 A) b' assms(2)])
    show "bA =  b'"
      by (fact 𝒱B_graph_neg(2)[OF A  pwffs 𝒱B_graph φ A ( b')])
  qed
  ultimately show ?case
    by force
next
  case (𝒱B_graph_conj A bA B bB)
  with 𝒱B_graph φ (A 𝒬 B) b' obtain bA' and bB'
    where "b' = bA'  bB'" and "𝒱B_graph φ A bA'" and "𝒱B_graph φ B bB'"
    by (cases rule: 𝒱B_graph.cases) simp_all
  moreover have "A  pwffs" and "B  pwffs"
    using pwffs_from_conj_pwff[OF 𝒱B_graph_conj.prems(1)] by blast+
  ultimately show ?case
    using 𝒱B_graph_conj.IH and 𝒱B_graph_conj.prems(2) by blast
next
  case (𝒱B_graph_disj A bA B bB)
  from 𝒱B_graph φ (A 𝒬 B) b' obtain bA' and bB'
    where "b' = bA'  bB'" and "𝒱B_graph φ A bA'" and "𝒱B_graph φ B bB'"
    by (cases rule: 𝒱B_graph.cases) simp_all
  moreover have "A  pwffs" and "B  pwffs"
    using pwffs_from_disj_pwff[OF 𝒱B_graph_disj.prems(1)] by blast+
  ultimately show ?case
    using 𝒱B_graph_disj.IH and 𝒱B_graph_disj.prems(2) by blast
next
  case (𝒱B_graph_imp A bA B bB)
  from 𝒱B_graph φ (A 𝒬 B) b' obtain bA' and bB'
    where "b' = bA'  bB'" and "𝒱B_graph φ A bA'" and "𝒱B_graph φ B bB'"
    by (cases rule: 𝒱B_graph.cases) simp_all
  moreover have "A  pwffs" and "B  pwffs"
    using pwffs_from_imp_pwff[OF 𝒱B_graph_imp.prems(1)] by blast+
  ultimately show ?case
    using 𝒱B_graph_imp.IH and 𝒱B_graph_imp.prems(2) by blast
next
  case (𝒱B_graph_eqv A bA B bB)
  with 𝒱B_graph φ (A 𝒬 B) b' obtain bA' and bB'
    where "b' = bA'  bB'" and "𝒱B_graph φ A bA'" and "𝒱B_graph φ B bB'"
    by (cases rule: 𝒱B_graph.cases) simp_all
  moreover have "A  pwffs" and "B  pwffs"
    using pwffs_from_eqv_pwff[OF 𝒱B_graph_eqv.prems(1)] by blast+
  ultimately show ?case
    using 𝒱B_graph_eqv.IH and 𝒱B_graph_eqv.prems(2) by blast
qed

lemma 𝒱B_graph_denotation_existence:
  assumes "A  pwffs"
  and "is_tv_assignment φ"
  shows "b. 𝒱B_graph φ A b"
using assms proof induction
  case (eqv_pwff A B)
  then obtain bA and bB where "𝒱B_graph φ A bA" and "𝒱B_graph φ B bB"
    by blast
  then show ?case
  proof (cases "A  Fo")
    case True
    then show ?thesis
      using eqv_pwff.IH and eqv_pwff.prems by blast
  next
    case False
    then have "A = Fo"
      by blast
    then show ?thesis
      using 𝒱B_graph_neg[OF 𝒱B_graph φ B bB] by auto
  qed
qed blast+

lemma 𝒱B_graph_is_functional:
  assumes "A  pwffs"
  and "is_tv_assignment φ"
  shows "∃!b. 𝒱B_graph φ A b"
  using assms and 𝒱B_graph_denotation_existence and 𝒱B_graph_denotation_uniqueness by blast

definition 𝒱B :: "(nat  V)  form  V" where
  [simp]: "𝒱B φ A = (THE b. 𝒱B_graph φ A b)"

lemma 𝒱B_equality:
  assumes "A  pwffs"
  and "is_tv_assignment φ"
  and "𝒱B_graph φ A b"
  shows "𝒱B φ A = b"
  unfolding 𝒱B_def using assms using 𝒱B_graph_denotation_uniqueness by blast

lemma 𝒱B_graph_𝒱B:
  assumes "A  pwffs"
  and "is_tv_assignment φ"
  shows "𝒱B_graph φ A (𝒱B φ A)"
  using 𝒱B_equality[OF assms] and 𝒱B_graph_is_functional[OF assms] by blast

named_theorems 𝒱B_simps

lemma 𝒱B_T [𝒱B_simps]:
  assumes "is_tv_assignment φ"
  shows "𝒱B φ To = T"
  by (rule 𝒱B_equality[OF T_pwff assms], intro 𝒱B_graph_T)

lemma 𝒱B_F [𝒱B_simps]:
  assumes "is_tv_assignment φ"
  shows "𝒱B φ Fo = F"
  by (rule 𝒱B_equality[OF F_pwff assms], intro 𝒱B_graph_F)

lemma 𝒱B_var [𝒱B_simps]:
  assumes "is_tv_assignment φ"
  shows "𝒱B φ (po) = φ p"
  by (rule 𝒱B_equality[OF var_pwff assms], intro 𝒱B_graph_var)

lemma 𝒱B_neg [𝒱B_simps]:
  assumes "A  pwffs"
  and "is_tv_assignment φ"
  shows "𝒱B φ (𝒬 A) =  𝒱B φ A"
  by (rule 𝒱B_equality[OF neg_pwff[OF assms(1)] assms(2)], intro 𝒱B_graph_neg 𝒱B_graph_𝒱B[OF assms])

lemma 𝒱B_disj [𝒱B_simps]:
  assumes "A  pwffs" and "B  pwffs"
  and "is_tv_assignment φ"
  shows "𝒱B φ (A 𝒬 B) = 𝒱B φ A  𝒱B φ B"
proof -
  from assms(1,3) have "𝒱B_graph φ A (𝒱B φ A)"
    by (intro 𝒱B_graph_𝒱B)
  moreover from assms(2,3) have "𝒱B_graph φ B (𝒱B φ B)"
    by (intro 𝒱B_graph_𝒱B)
  ultimately have "𝒱B_graph φ (A 𝒬 B) (𝒱B φ A  𝒱B φ B)"
    by (intro 𝒱B_graph_disj)
  with assms show ?thesis
    using disj_pwff by (intro 𝒱B_equality)
qed

lemma 𝒱B_conj [𝒱B_simps]:
  assumes "A  pwffs" and "B  pwffs"
  and "is_tv_assignment φ"
  shows "𝒱B φ (A 𝒬 B) = 𝒱B φ A  𝒱B φ B"
proof -
  from assms(1,3) have "𝒱B_graph φ A (𝒱B φ A)"
    by (intro 𝒱B_graph_𝒱B)
  moreover from assms(2,3) have "𝒱B_graph φ B (𝒱B φ B)"
    by (intro 𝒱B_graph_𝒱B)
  ultimately have "𝒱B_graph φ (A 𝒬 B) (𝒱B φ A  𝒱B φ B)"
    by (intro 𝒱B_graph_conj)
  with assms show ?thesis
    using conj_pwff by (intro 𝒱B_equality)
qed

lemma 𝒱B_imp [𝒱B_simps]:
  assumes "A  pwffs" and "B  pwffs"
  and "is_tv_assignment φ"
  shows "𝒱B φ (A 𝒬 B) = 𝒱B φ A  𝒱B φ B"
proof -
  from assms(1,3) have "𝒱B_graph φ A (𝒱B φ A)"
    by (intro 𝒱B_graph_𝒱B)
  moreover from assms(2,3) have "𝒱B_graph φ B (𝒱B φ B)"
    by (intro 𝒱B_graph_𝒱B)
  ultimately have "𝒱B_graph φ (A 𝒬 B) (𝒱B φ A  𝒱B φ B)"
    by (intro 𝒱B_graph_imp)
  with assms show ?thesis
    using imp_pwff by (intro 𝒱B_equality)
qed

lemma 𝒱B_eqv [𝒱B_simps]:
  assumes "A  pwffs" and "B  pwffs"
  and "is_tv_assignment φ"
  shows "𝒱B φ (A 𝒬 B) = 𝒱B φ A  𝒱B φ B"
proof (cases "A = Fo")
  case True
  then show ?thesis
    using 𝒱B_F[OF assms(3)] and 𝒱B_neg[OF assms(2,3)] by force
next
  case False
  from assms(1,3) have "𝒱B_graph φ A (𝒱B φ A)"
    by (intro 𝒱B_graph_𝒱B)
  moreover from assms(2,3) have "𝒱B_graph φ B (𝒱B φ B)"
    by (intro 𝒱B_graph_𝒱B)
  ultimately have "𝒱B_graph φ (A 𝒬 B) (𝒱B φ A  𝒱B φ B)"
    using False by (intro 𝒱B_graph_eqv)
  with assms show ?thesis
    using eqv_pwff by (intro 𝒱B_equality)
qed

declare pwffs.intros [𝒱B_simps]

lemma pwff_denotation_function_existence:
  shows "is_pwff_denotation_function 𝒱B"
  using 𝒱B_simps by simp

text ‹Tautologies:›

definition is_tautology :: "form  bool" where
  [iff]: "is_tautology A  A  pwffs  (φ. is_tv_assignment φ  𝒱B φ A = T)"

lemma tautology_is_wffo:
  assumes "is_tautology A"
  shows "A  wffs⇘o⇙"
  using assms and pwffs_subset_of_wffso by blast

lemma propositional_implication_reflexivity_is_tautology:
  shows "is_tautology (po𝒬 po)"
  using 𝒱B_simps by simp

lemma propositional_principle_of_simplification_is_tautology:
  shows "is_tautology (po𝒬 (ro𝒬 po))"
  using 𝒱B_simps by simp

lemma closed_pwff_denotation_uniqueness:
  assumes "A  pwffs" and "free_vars A = {}"
  obtains b where "φ. is_tv_assignment φ  𝒱B φ A = b"
  using assms
  by (meson closed_pwff_is_meaningful_regardless_of_assignment pwff_denotation_function_existence)

lemma pwff_substitution_simps:
  shows "S {(p, o)  A} To = To"
  and "S {(p, o)  A} Fo = Fo"
  and "S {(p, o)  A} (p'o) = (if p = p' then A else (p'o))"
  and "S {(p, o)  A} (𝒬 B) = 𝒬 (S {(p, o)  A} B)"
  and "S {(p, o)  A} (B 𝒬 C) = (S {(p, o)  A} B) 𝒬 (S {(p, o)  A} C)"
  and "S {(p, o)  A} (B 𝒬 C) = (S {(p, o)  A} B) 𝒬 (S {(p, o)  A} C)"
  and "S {(p, o)  A} (B 𝒬 C) = (S {(p, o)  A} B) 𝒬 (S {(p, o)  A} C)"
  and "S {(p, o)  A} (B 𝒬 C) = (S {(p, o)  A} B) 𝒬 (S {(p, o)  A} C)"
  by simp_all

lemma pwff_substitution_in_pwffs:
  assumes "A  pwffs" and "B  pwffs"
  shows "S {(p, o)  A} B  pwffs"
using assms(2) proof induction
  case T_pwff
  then show ?case
    using pwffs.T_pwff by simp
next
  case F_pwff
  then show ?case
    using pwffs.F_pwff by simp
next
  case (var_pwff p)
  from assms(1) show ?case
    using pwffs.var_pwff by simp
next
  case (neg_pwff A)
  then show ?case
    using pwff_substitution_simps(4) and pwffs.neg_pwff by simp
next
  case (conj_pwff A B)
  then show ?case
    using pwff_substitution_simps(5) and pwffs.conj_pwff by simp
next
  case (disj_pwff A B)
  then show ?case
    using pwff_substitution_simps(6) and pwffs.disj_pwff by simp
next
  case (imp_pwff A B)
  then show ?case
    using pwff_substitution_simps(7) and pwffs.imp_pwff by simp
next
  case (eqv_pwff A B)
  then show ?case
    using pwff_substitution_simps(8) and pwffs.eqv_pwff by simp
qed

lemma pwff_substitution_denotation:
  assumes "A  pwffs" and "B  pwffs"
  and "is_tv_assignment φ"
  shows "𝒱B φ (S {(p, o)  A} B) = 𝒱B (φ(p := 𝒱B φ A)) B"
proof -
  from assms(1,3) have "is_tv_assignment (φ(p := 𝒱B φ A))"
    using 𝒱B_graph_denotation_is_truth_value[OF 𝒱B_graph_𝒱B] by simp
  with assms(2,1,3) show ?thesis
    using 𝒱B_simps and pwff_substitution_in_pwffs by induction auto
qed

lemma pwff_substitution_tautology_preservation:
  assumes "is_tautology B" and "A  pwffs"
  and "(p, o)  free_vars B"
  shows "is_tautology (S {(p, o)  A} B)"
proof (safe, fold is_tv_assignment_def)
  from assms(1,2) show "S {(p, o)  A} B  pwffs"
    using pwff_substitution_in_pwffs by blast
next
  fix φ
  assume "is_tv_assignment φ"
  with assms(1,2) have "𝒱B φ (S {(p, o)  A} B) = 𝒱B (φ(p := 𝒱B φ A)) B"
    using pwff_substitution_denotation by blast
  moreover from is_tv_assignment φ and assms(2) have "is_tv_assignment (φ(p := 𝒱B φ A))"
    using 𝒱B_graph_denotation_is_truth_value[OF 𝒱B_graph_𝒱B] by simp
  with assms(1) have "𝒱B (φ(p := 𝒱B φ A)) B = T"
    by fastforce
  ultimately show "𝒱B φ S {(p, o)  A} B = T"
    by (simp only:)
qed

lemma closed_pwff_substitution_free_vars:
  assumes "A  pwffs" and "B  pwffs"
  and "free_vars A = {}"
  and "(p, o)  free_vars B"
  shows "free_vars (S {(p, o)  A} B) = free_vars B - {(p, o)}" (is free_vars (S  B) = _)
using assms(2,4) proof induction
  case (conj_pwff C D)
  have "free_vars (S  (C 𝒬 D)) = free_vars ((S  C) 𝒬 (S  D))"
    by simp
  also have " = free_vars (S  C)  free_vars (S  D)"
    by (fact conj_fv)
  finally have *: "free_vars (S  (C 𝒬 D)) = free_vars (S  C)  free_vars (S  D)" .
  from conj_pwff.prems consider
    (a) "(p, o)  free_vars C" and "(p, o)  free_vars D"
  | (b) "(p, o)  free_vars C" and "(p, o)  free_vars D"
  | (c) "(p, o)  free_vars C" and "(p, o)  free_vars D"
    by auto
  from this and * and conj_pwff.IH show ?case
    using free_var_singleton_substitution_neutrality by cases auto
next
  case (disj_pwff C D)
  have "free_vars (S  (C 𝒬 D)) = free_vars ((S  C) 𝒬 (S  D))"
    by simp
  also have " = free_vars (S  C)  free_vars (S  D)"
    by (fact disj_fv)
  finally have *: "free_vars (S  (C 𝒬 D)) = free_vars (S  C)  free_vars (S  D)" .
  from disj_pwff.prems consider
    (a) "(p, o)  free_vars C" and "(p, o)  free_vars D"
  | (b) "(p, o)  free_vars C" and "(p, o)  free_vars D"
  | (c) "(p, o)  free_vars C" and "(p, o)  free_vars D"
    by auto
  from this and * and disj_pwff.IH show ?case
    using free_var_singleton_substitution_neutrality by cases auto
next
  case (imp_pwff C D)
  have "free_vars (S  (C 𝒬 D)) = free_vars ((S  C) 𝒬 (S  D))"
    by simp
  also have " = free_vars (S  C)  free_vars (S  D)"
    by (fact imp_fv)
  finally have *: "free_vars (S  (C 𝒬 D)) = free_vars (S  C)  free_vars (S  D)" .
  from imp_pwff.prems consider
    (a) "(p, o)  free_vars C" and "(p, o)  free_vars D"
  | (b) "(p, o)  free_vars C" and "(p, o)  free_vars D"
  | (c) "(p, o)  free_vars C" and "(p, o)  free_vars D"
    by auto
  from this and * and imp_pwff.IH show ?case
    using free_var_singleton_substitution_neutrality by cases auto
next
  case (eqv_pwff C D)
  have "free_vars (S  (C 𝒬 D)) = free_vars ((S  C) 𝒬 (S  D))"
    by simp
  also have " = free_vars (S  C)  free_vars (S  D)"
    by (fact eqv_fv)
  finally have *: "free_vars (S  (C 𝒬 D)) = free_vars (S  C)  free_vars (S  D)" .
  from eqv_pwff.prems consider
    (a) "(p, o)  free_vars C" and "(p, o)  free_vars D"
  | (b) "(p, o)  free_vars C" and "(p, o)  free_vars D"
  | (c) "(p, o)  free_vars C" and "(p, o)  free_vars D"
    by auto
  from this and * and eqv_pwff.IH show ?case
    using free_var_singleton_substitution_neutrality by cases auto
qed (use assms(3) in force+)

text ‹Substitution in a pwff:›

definition is_pwff_substitution where
  [iff]: "is_pwff_substitution θ  is_substitution θ  ((x, α)  fmdom' θ. α = o)"

text ‹Tautologous pwff:›

definition is_tautologous :: "form  bool" where
  [iff]: "is_tautologous B  (θ A. is_tautology A  is_pwff_substitution θ  B = S θ A)"

lemma tautologous_is_wffo:
  assumes "is_tautologous A"
  shows "A  wffs⇘o⇙"
  using assms and substitution_preserves_typing and tautology_is_wffo by blast

lemma implication_reflexivity_is_tautologous:
  assumes "A  wffs⇘o⇙"
  shows "is_tautologous (A 𝒬 A)"
proof -
  let  = "{(𝔵, o)  A}"
  have "is_tautology (𝔵o𝒬 𝔵o)"
    by (fact propositional_implication_reflexivity_is_tautology)
  moreover have "is_pwff_substitution "
    using assms by auto
  moreover have "A 𝒬 A = S  (𝔵o𝒬 𝔵o)"
    by simp
  ultimately show ?thesis
    by blast
qed

lemma principle_of_simplification_is_tautologous:
  assumes "A  wffs⇘o⇙" and "B  wffs⇘o⇙"
  shows "is_tautologous (A 𝒬 (B 𝒬 A))"
proof -
  let  = "{(𝔵, o)  A, (𝔶, o)  B}"
  have "is_tautology (𝔵o𝒬 (𝔶o𝒬 𝔵o))"
    by (fact propositional_principle_of_simplification_is_tautology)
  moreover have "is_pwff_substitution "
    using assms by auto
  moreover have "A 𝒬 (B 𝒬 A) = S  (𝔵o𝒬 (𝔶o𝒬 𝔵o))"
    by simp
  ultimately show ?thesis
    by blast
qed

lemma pseudo_modus_tollens_is_tautologous:
  assumes "A  wffs⇘o⇙" and "B  wffs⇘o⇙"
  shows "is_tautologous ((A 𝒬 𝒬 B) 𝒬 (B 𝒬 𝒬 A))"
proof -
  let  = "{(𝔵, o)  A, (𝔶, o)  B}"
  have "is_tautology ((𝔵o𝒬 𝒬 𝔶o) 𝒬 (𝔶o𝒬 𝒬 𝔵o))"
    using 𝒱B_simps by (safe, fold is_tv_assignment_def, simp only:) simp
  moreover have "is_pwff_substitution "
    using assms by auto
  moreover have "(A 𝒬 𝒬 B) 𝒬 (B 𝒬 𝒬 A) = S  ((𝔵o𝒬 𝒬 𝔶o) 𝒬 (𝔶o𝒬 𝒬 𝔵o))"
    by simp
  ultimately show ?thesis
    by blast
qed

end