Theory FOL_Axiomatic_Variant

(*
  File:      FOL_Axiomatic_Variant.thy
  Author:    Asta Halkjær From

  This work is a formalization of the soundness and completeness of an axiomatic system
  for first-order logic. The proof system is based on System Q1 by Smullyan
  and the completeness proof follows his textbook "First-Order Logic" (Springer-Verlag 1968).
  The completeness proof is in the Henkin style where a consistent set
  is extended to a maximal consistent set using Lindenbaum's construction
  and Henkin witnesses are added during the construction to ensure saturation as well.
  The resulting set is a Hintikka set which, by the model existence theorem, is satisfiable
  in the Herbrand universe.

  This variant uses free variables as Henkin witnesses. This gives completeness for syntax
  with only finitely many available constants.
*)

theory FOL_Axiomatic_Variant imports "HOL-Library.Countable" begin

section ‹Syntax›

datatype 'f tm
  = Var nat (#)
  | Fun 'f 'f tm list ()

datatype ('f, 'p) fm
  = Falsity ()
  | Pre 'p 'f tm list ()
  | Imp ('f, 'p) fm ('f, 'p) fm (infixr  55)
  | Uni ('f, 'p) fm ()

abbreviation Neg (¬ _› [70] 70) where ¬ p  p  

term (  ''P'' [''f'' [#0]])

section ‹Semantics›

definition shift :: (nat  'a)  nat  'a  nat  'a
  (‹__:_ [90, 0, 0] 91) where
  En:x = (λm. if m < n then E m else if m = n then x else E (m-1))

primrec semantics_tm (_, _) where
  E, F (#n) = E n
| E, F (f ts) = F f (map E, F ts)

primrec semantics_fm (_, _, _) where
  _, _, _  = False
| E, F, G (P ts) = G P (map E, F ts)
| E, F, G (p  q) = (E, F, G p  E, F, G q)
| E, F, G (p) = (x. E0:x, F, G p)

proposition E, F, G ((P [# 0])  P [ a []])
  by (simp add: shift_def)

section ‹Operations›

subsection ‹Shift›

lemma shift_eq [simp]: n = m  (En:x) m = x
  by (simp add: shift_def)

lemma shift_gt [simp]: m < n  (En:x) m = E m
  by (simp add: shift_def)

lemma shift_lt [simp]: n < m  (En:x) m = E (m-1)
  by (simp add: shift_def)

lemma shift_commute [simp]: En:y0:x = E0:xn+1:y
proof
  fix m
  show (En:y0:x) m = (E0:xn+1:y) m
    unfolding shift_def by (cases m) simp_all
qed

subsection ‹Variables›

primrec vars_tm where
  vars_tm (#n) = [n]
| vars_tm (_ ts) = concat (map vars_tm ts)

primrec vars_fm where
  vars_fm  = []
| vars_fm (_ ts) = concat (map vars_tm ts)
| vars_fm (p  q) = vars_fm p @ vars_fm q
| vars_fm (p) = vars_fm p

abbreviation vars S  p  S. set (vars_fm p)

primrec max_list :: nat list  nat where
  max_list [] = 0
| max_list (x # xs) = max x (max_list xs)

lemma max_list_append: max_list (xs @ ys) = max (max_list xs) (max_list ys)
  by (induct xs) auto

lemma upd_vars_tm [simp]: n  set (vars_tm t)  E(n := x), F t = E, F t
  by (induct t) (auto cong: map_cong)

lemma shift_upd_commute: m  n  (E(n := x)m:y) = ((Em:y)(n + 1 := x))
  unfolding shift_def by fastforce

lemma max_list_concat: xs  set xss  max_list xs  max_list (concat xss)
  by (induct xss) (auto simp: max_list_append)

lemma max_list_in: max_list xs < n  n  set xs
  by (induct xs) auto

lemma upd_vars_fm [simp]: max_list (vars_fm p) < n  E(n := x), F, G p = E, F, G p
proof (induct p arbitrary: E n)
  case (Pre P ts)
  moreover have max_list (concat (map vars_tm ts)) < n
    using Pre.prems max_list_concat by simp
  then have n  set (concat (map vars_tm ts))
    using max_list_in by blast
  then have t  set ts. n  set (vars_tm t)
    by simp
  ultimately show ?case
    using upd_vars_tm by (metis list.map_cong semantics_fm.simps(2))
next
  case (Uni p)
  have ?case = ((y. E(n := x)0:y, F, G p) = (y. E0:y, F, G p))
    by (simp add: fun_upd_def)
  also have  = ((y. (E0:y)(n + 1 := x), F, G p) = (y. E0:y, F, G p))
    by (simp add: shift_upd_commute)
  finally show ?case
    using Uni by fastforce
qed (auto simp: max_list_append cong: map_cong)

abbreviation max_var p  max_list (vars_fm p)

subsection ‹Instantiation›

primrec lift_tm () where
  (#n) = #(n+1)
| (f ts) = f (map  ts)

primrec inst_tm (‹_'⟪_'/_'⟫ [90, 0, 0] 91) where
  (#n)s/m = (if n < m then #n else if n = m then s else #(n-1))
| (f ts)s/m = f (map (λt. ts/m) ts)

primrec inst_fm (‹_'⟨_'/_'⟩ [90, 0, 0] 91) where
  _/_ = 
| (P ts)s/m = P (map (λt. ts/m) ts)
| (p  q)s/m = (ps/m  qs/m)
| (p)s/m = (ps/m+1)

lemma lift_lemma [simp]: E0:x, F (t) = E, F t
  by (induct t) (auto cong: map_cong)

lemma inst_tm_semantics [simp]: E, F (ts/m) = Em:E, F s, F t
  by (induct t) (auto cong: map_cong)

lemma inst_fm_semantics [simp]: E, F, G (pt/m) = Em:E, F t, F, G p
  by (induct p arbitrary: E m t) (auto cong: map_cong)

subsection ‹Size›

text ‹The built-in size› is not invariant under substitution.›

primrec size_fm where
  size_fm  = 1
| size_fm (_ _) = 1
| size_fm (p  q) = 1 + size_fm p + size_fm q
| size_fm (p) = 1 + size_fm p

lemma size_inst_fm [simp]:
  size_fm (pt/m) = size_fm p
  by (induct p arbitrary: m t) auto

section ‹Propositional Semantics›

primrec boolean where
  boolean _ _  = False
| boolean G _ (P ts) = G P ts
| boolean G A (p  q) = (boolean G A p  boolean G A q)
| boolean _ A (p) = A (p)

abbreviation tautology p  G A. boolean G A p

proposition tautology ((P [#0])  (P [#0]))
  by simp

lemma boolean_semantics: boolean (λa. G a  map E, F) E, F, G = E, F, G
proof
  fix p
  show boolean (λa. G a  map E, F) E, F, G p = E, F, G p
    by (induct p) simp_all
qed

lemma tautology: tautology p  E, F, G p
  using boolean_semantics by metis

proposition p. (E F G. E, F, G p)  ¬ tautology p
  by (metis boolean.simps(4) fm.simps(36) semantics_fm.simps(1,3,4))

section ‹Calculus›

text ‹Adapted from System Q1 by Smullyan in First-Order Logic (1968)›

inductive Axiomatic ( _› [50] 50) where
  TA: tautology p   p
| IA:  p  pt/0
| MP:  p  q   p   q
| GR:  q  p#n/0  max_var p < n  max_var q < n   q  p

lemmas
  TA[simp]
  MP[trans, dest]
  GR[intro]

text ‹We simulate assumptions on the lhs of ⊢› with a chain of implications on the rhs.›

primrec imply (infixr  56) where
  ([]  q) = q
| (p # ps  q) = (p  ps  q)

abbreviation Axiomatic_assms (‹_  _› [50, 50] 50) where
  ps  q   ps  q

section ‹Soundness›

theorem soundness:  p  E, F, G p
proof (induct p arbitrary: E F rule: Axiomatic.induct)
  case (GR q p n)
  then have E(n := x), F, G (q  p#n/0) for x
    by blast
  then have E(n := x), F, G q  E(n := x), F, G (p#n/0) for x
    by simp
  then have E, F, G q  E(n := x), F, G (p#n/0) for x
    using GR.hyps(3-4) by simp
  then have E, F, G q  (x. E(n := x), F, G (p#n/0))
    by blast
  then have E, F, G q  (x. E(n := x)0:x, F, G p)
    by simp
  then have E, F, G q  (x. (E0:x)(n + 1 := x), F, G p)
    using shift_upd_commute by (metis zero_le)
  moreover have max_list (vars_fm p) < n
    using GR.hyps(3) by (simp add: max_list_append)
  ultimately have E, F, G q  (x. E0:x, F, G p)
    using upd_vars_fm by simp
  then show ?case
    by simp
qed (auto simp: tautology)

corollary ¬ ( )
  using soundness by fastforce

section ‹Derived Rules›

lemma AS:  (p  q  r)  (p  q)  p  r
  by auto

lemma AK:  q  p  q
  by auto

lemma Neg:  ¬ ¬ p  p
  by auto

lemma contraposition:
   (p  q)  ¬ q  ¬ p
   (¬ q  ¬ p)  p  q
  by (auto intro: TA)

lemma GR':  ¬ p#n/0  q  max_var p < n  max_var q < n   ¬ p  q
proof -
  assume *:  ¬ p#n/0  q and n: max_var p < n max_var q < n
  have  ¬ q  ¬ ¬ p#n/0
    using * contraposition(1) by fast
  then have  ¬ q  p#n/0
    by (meson AK AS MP Neg)
  then have  ¬ q  p
    using n by auto
  then have  ¬ p  ¬ ¬ q
    using contraposition(1) by fast
  then show ?thesis
    by (meson AK AS MP Neg)
qed

lemma Imp3:  (p  q  r)  ((s  p)  (s  q)  s  r)
  by auto

lemma imply_ImpE:  ps  p  ps  (p  q)  ps  q
  by (induct ps) (auto intro: Imp3 MP)

lemma MP' [trans, dest]: ps  p  q  ps  p  ps  q
  using imply_ImpE by fast

lemma imply_Cons [intro]: ps  q  p # ps  q
  by (auto intro: MP AK)

lemma imply_head [intro]: p # ps  p
proof (induct ps)
  case (Cons q ps)
  then show ?case
    by (metis AK MP' imply.simps(1-2))
qed auto

lemma imply_lift_Imp [simp]:
  assumes  p  q
  shows  p  ps  q
  using assms MP MP' imply_head by (metis imply.simps(2))

lemma add_imply [simp]:  q  ps  q
  using MP imply_head by (auto simp del: TA)

lemma imply_mem [simp]: p  set ps  ps  p
proof (induct ps)
  case (Cons q ps)
  then show ?case
    by (metis imply_Cons imply_head set_ConsD)
qed simp

lemma deduct1: ps  p  q  p # ps  q
  by (meson MP' imply_Cons imply_head)

lemma imply_append [iff]: (ps @ qs  r) = (ps  qs  r)
  by (induct ps) simp_all

lemma imply_swap_append: ps @ qs  r  qs @ ps  r
proof (induct qs arbitrary: ps)
  case (Cons q qs)
  then show ?case
    by (metis deduct1 imply.simps(2) imply_append)
qed simp

lemma deduct2: p # ps  q  ps  p  q
  by (metis imply.simps(1-2) imply_append imply_swap_append)

lemmas deduct [iff] = deduct1 deduct2

lemma cut [trans, dest]: p # ps  r  q # ps  p  q # ps  r
  by (meson MP' deduct(2) imply_Cons)

lemma Boole: (¬ p) # ps    ps  p
  by (meson MP' Neg add_imply deduct(2))

lemma imply_weaken: ps  q  set ps  set ps'  ps'  q
proof (induct ps arbitrary: q)
  case (Cons p ps)
  then show ?case
    by (metis MP' deduct(2) imply_mem insert_subset list.simps(15))
qed simp

section ‹Consistent›

definition consistent S  S'. set S'  S  S'  

lemma UN_finite_bound:
  assumes finite A and A  (n. f n)
  shows m :: nat. A  (n  m. f n)
  using assms
proof (induct rule: finite_induct)
  case (insert x A)
  then obtain m where A  (n  m. f n)
    by fast
  then have A  (n  (m + k). f n) for k
    by fastforce
  moreover obtain m' where x  f m'
    using insert(4) by blast
  ultimately have {x}  A  (n  m + m'. f n)
    by auto
  then show ?case
    by blast
qed simp

lemma split_list:
  assumes x  set A
  shows set (x # removeAll x A) = set A  x  set (removeAll x A)
  using assms by auto

lemma imply_vars_fm: vars_fm (ps  q) = concat (map vars_fm ps) @ vars_fm q
  by (induct ps) auto

lemma inconsistent_fm:
  assumes consistent S and ¬ consistent ({p}  S)
  obtains S' where set S'  S and p # S'  
proof -
  obtain S' where S': set S'  {p}  S p  set S' S'  
    using assms unfolding consistent_def by blast
  then obtain S'' where S'': set (p # S'') = set S' p  set S''
    using split_list by metis
  then have p # S''  
    using S'   imply_weaken by blast
  then show ?thesis
    using that S'' S'(1)
    by (metis Diff_insert_absorb Diff_subset_conv list.simps(15))
qed

definition max_set :: nat set  nat where
  max_set X  if X = {} then 0 else Max X

lemma max_list_in_Cons: xs  []  max_list xs  set xs
proof (induct xs)
  case Nil
  then show ?case
    by simp
next
  case (Cons x xs)
  then show ?case
    by (metis linorder_not_less list.set_intros(1-2) max.absorb2 max.absorb3
        max_list.simps(1-2) max_nat.right_neutral)
qed

lemma max_list_max: x  set xs. x  max_list xs
  by (induct xs) auto

lemma max_list_in_set: finite S  set xs  S  max_list xs  max_set S
  unfolding max_set_def using max_list_in_Cons
  by (metis (mono_tags, lifting) Max_ge bot.extremum_uniqueI bot_nat_0.extremum max_list.simps(1)
      set_empty subsetD)

lemma consistent_add_witness:
  assumes consistent S and (¬ p)  S
    and finite (vars S) and max_set (vars S) < n
  shows consistent ({¬ p#n/0}  S)
  unfolding consistent_def
proof
  assume S'. set S'  {¬ p#n/0}  S  S'  
  then obtain S' where set S'  S and (¬ p#n/0) # S'  
    using assms inconsistent_fm unfolding consistent_def by metis
  then have  ¬ p#n/0  S'  
    by simp
  moreover have max_list (vars_fm p) < n
    using assms(2-4) max_list_in_set by fastforce
  moreover have p  set S'. max_list (vars_fm p) < n
    using set S'  S assms(3-4) max_list_in_set
    by (meson Union_upper image_eqI order_le_less_trans subsetD)
  then have max_list (concat (map vars_fm S')) < n
    using assms(4) by (induct S') (auto simp: max_list_append)
  then have max_list (vars_fm (S'  )) < n
    unfolding imply_vars_fm max_list_append by simp
  ultimately have  ¬ p  S'  
    using GR' unfolding max_list_append by auto
  then have (¬ p) # S'  
    by simp
  moreover have set ((¬ p) # S')  S
    using set S'  S assms(2) by simp
  ultimately show False
    using assms(1) unfolding consistent_def by blast
qed

lemma consistent_add_instance:
  assumes consistent S and p  S
  shows consistent ({pt/0}  S)
  unfolding consistent_def
proof
  assume S'. set S'  {pt/0}  S  S'  
  then obtain S' where set S'  S and pt/0 # S'  
    using assms inconsistent_fm unfolding consistent_def by blast
  moreover have  p  pt/0
    using IA by blast
  ultimately have p # S'  
    by (meson add_imply cut deduct(1))
  moreover have set ((p) # S')  S
    using set S'  S assms(2) by simp
  ultimately show False
    using assms(1) unfolding consistent_def by blast
qed

section ‹Extension›

fun witness where
  witness used (¬ p) = {¬ p#(SOME n. max_set used < n)/0}
| witness _ _ = {}

primrec extend where
  extend S f 0 = S
| extend S f (Suc n) =
   (let Sn = extend S f n in
     if consistent ({f n}  Sn)
     then witness (vars ({f n}  Sn)) (f n)  {f n}  Sn
     else Sn)

definition Extend S f  n. extend S f n

lemma Extend_subset: S  Extend S f
  unfolding Extend_def by (metis Union_upper extend.simps(1) range_eqI)

lemma extend_bound: (n  m. extend S f n) = extend S f m
  by (induct m) (simp_all add: atMost_Suc Let_def)

lemma finite_vars_witness [simp]: finite (vars (witness used p))
  by (induct used p rule: witness.induct) simp_all

lemma finite_vars_extend [simp]: finite (vars S)  finite (vars (extend S f n))
  by (induct n) (simp_all add: Let_def)

lemma max_list_mono: set xs  set ys  max_list xs  max_list ys
  using max_list_max max_list_in_Cons
  by (metis less_nat_zero_code linorder_not_le max_list.simps(1) subset_code(1))

lemma consistent_witness:
  fixes p :: ('f, 'p) fm
  assumes consistent S and p  S and vars S  used and finite used
  shows consistent (witness used p  S)
  using assms
proof (induct used p rule: witness.induct)
  case (1 used p)
  moreover have n. max_set used < n
    by blast
  ultimately obtain n where n: witness used (¬ p) = {¬ p#n/0} and max_set used < n
    by (metis someI_ex witness.simps(1))
  then have max_set (vars S) < n
    using 1(3-4) max_list_mono order_le_less_trans
    by (metis (no_types, lifting) Max.subset_imp bot.extremum_uniqueI less_nat_zero_code linorder_neqE_nat max_set_def)
  moreover have finite (vars S)
    using 1(3-4) infinite_super by blast
  ultimately show ?case
    using 1 n(1) consistent_add_witness by metis
qed (auto simp: assms)

lemma consistent_extend:
  fixes f :: nat  ('f, 'p) fm
  assumes consistent S finite (vars S)
  shows consistent (extend S f n)
  using assms
proof (induct n)
  case (Suc n)
  then show ?case
    using consistent_witness[where S={f n}  _] by (auto simp: Let_def)
qed simp

lemma consistent_Extend:
  fixes f :: nat  ('f, 'p) fm
  assumes consistent S finite (vars S)
  shows consistent (Extend S f)
  unfolding consistent_def
proof
  assume S'. set S'  Extend S f  S'  
  then obtain S' where S'   and set S'  Extend S f
    unfolding consistent_def by blast
  then obtain m where set S'  (n  m. extend S f n)
    unfolding Extend_def using UN_finite_bound by (metis List.finite_set)
  then have set S'  extend S f m
    using extend_bound by blast
  moreover have consistent (extend S f m)
    using assms consistent_extend by blast
  ultimately show False
    unfolding consistent_def using S'   by blast
qed

section ‹Maximal›

definition maximal S  p. p  S  ¬ consistent ({p}  S)

lemma maximal_exactly_one:
  assumes consistent S and maximal S
  shows p  S  (¬ p)  S
proof
  assume p  S
  show (¬ p)  S
  proof
    assume (¬ p)  S
    then have set [p, ¬ p]  S
      using p  S by simp
    moreover have [p, ¬ p]  
      by blast
    ultimately show False
      using consistent S unfolding consistent_def by blast
  qed
next
  assume (¬ p)  S
  then have ¬ consistent ({¬ p}  S)
    using maximal S unfolding maximal_def by blast
  then obtain S' where set S'  S (¬ p) # S'  
    using consistent S inconsistent_fm by blast
  then have S'  p
    using Boole by blast
  have consistent ({p}  S)
    unfolding consistent_def
  proof
    assume S'. set S'  {p}  S  S'  
    then obtain S'' where set S''  S and p # S''  
      using assms inconsistent_fm unfolding consistent_def by blast
    then have S' @ S''  
      using S'  p by (metis MP' add_imply imply.simps(2) imply_append)
    moreover have set (S' @ S'')  S
      using set S'  S set S''  S by simp
    ultimately show False
      using consistent S unfolding consistent_def by blast
  qed
  then show p  S
    using maximal S unfolding maximal_def by blast
qed

lemma maximal_Extend:
  assumes surj f
  shows maximal (Extend S f)
proof (rule ccontr)
  assume ¬ maximal (Extend S f)
  then obtain p where
    p  Extend S f and consistent ({p}  Extend S f)
    unfolding maximal_def using assms consistent_Extend by blast
  obtain k where k: f k = p
    using surj f unfolding surj_def by metis
  then have p  extend S f (Suc k)
    using p  Extend S f unfolding Extend_def by blast
  then have ¬ consistent ({p}  extend S f k)
    using k by (auto simp: Let_def)
  moreover have {p}  extend S f k  {p}  Extend S f
    unfolding Extend_def by blast
  ultimately have ¬ consistent ({p}  Extend S f)
    unfolding consistent_def by auto
  then show False
    using consistent ({p}  Extend S f) by blast
qed

section ‹Saturation›

definition saturated S  p. (¬ p)  S  (n. (¬ p#n/0)  S)

lemma saturated_Extend:
  assumes consistent (Extend S f) and surj f
  shows saturated (Extend S f)
proof (rule ccontr)
  assume ¬ saturated (Extend S f)
  then obtain p where p: (¬ p)  Extend S f n. (¬ p#n/0)  Extend S f
    unfolding saturated_def by blast
  obtain k where k: f k = (¬ p)
    using surj f unfolding surj_def by metis

  have extend S f k  Extend S f
    unfolding Extend_def by auto
  then have consistent ({¬ p}  extend S f k)
    using assms(1) p(1) unfolding consistent_def by blast
  then have n. extend S f (Suc k) = {¬ p#n/0}  {¬ p}  extend S f k
    using k by (auto simp: Let_def)
  moreover have extend S f (Suc k)  Extend S f
    unfolding Extend_def by blast
  ultimately show False
    using p(2) by auto
qed

section ‹Hintikka›

locale Hintikka =
  fixes H :: ('f, 'p) fm set
  assumes
    NoFalsity:   H and
    ImpP: (p  q)  H  p  H  q  H and
    ImpN: (p  q)  H  p  H  q  H and
    UniP: p  H  t. pt/0  H and
    UniN: p  H  n. p#n/0  H

subsection ‹Model Existence›

abbreviation hmodel (_) where H  #, , λP ts. Pre P ts  H

lemma semantics_tm_id [simp]:
  #,  t = t
  by (induct t) (auto cong: map_cong)

lemma semantics_tm_id_map [simp]: map #,  ts = ts
  by (auto cong: map_cong)

theorem Hintikka_model:
  assumes Hintikka H
  shows p  H  H p
proof (induct p rule: wf_induct[where r=measure size_fm])
  case 1
  then show ?case ..
next
  case (2 x)
  show x  H  H x
  proof (cases x; safe)
    case Falsity
    assume   H
    then have False
      using assms Hintikka.NoFalsity by fast
    then show H  ..
  next
    case Falsity
    assume H 
    then have False
      by simp
    then show   H ..
  next
    case (Pre P ts)
    assume P ts  H
    then show H (P ts)
      by simp
  next
    case (Pre P ts)
    assume H (P ts)
    then show P ts  H
      by simp
  next
    case (Imp p q)
    assume (p  q)  H
    then have p  H  q  H
      using assms Hintikka.ImpP by blast
    then have ¬ H p  H q
      using 2 Imp by simp
    then show H (p  q)
      by simp
  next
    case (Imp p q)
    assume H (p  q)
    then have ¬ H p  H q
      by simp
    then have p  H  q  H
      using 2 Imp by simp
    then show (p  q)  H
      using assms Hintikka.ImpN by blast
  next
    case (Uni p)
    assume p  H
    then have t. pt/0  H
      using assms Hintikka.UniP by metis
    then have t. H (pt/0)
      using 2 Uni by simp
    then show H (p)
      by simp
  next
    case (Uni p)
    assume H (p)
    then have t. H (pt/0)
      by simp
    then have t. pt/0  H
      using 2 Uni by simp
    then show p  H
      using assms Hintikka.UniN by blast
  qed
qed

subsection ‹Maximal Consistent Sets are Hintikka Sets›

lemma inconsistent_head:
  assumes consistent S and maximal S and p  S
  obtains S' where set S'  S and p # S'  
  using assms inconsistent_fm unfolding consistent_def maximal_def by metis

lemma inconsistent_parts [simp]:
  assumes ps   and set ps  S
  shows ¬ consistent S
  using assms unfolding consistent_def by blast

lemma Hintikka_Extend:
  fixes H :: ('f, 'p) fm set
  assumes consistent H and maximal H and saturated H
  shows Hintikka H
proof
  show   H
  proof
    assume   H
    moreover have []  
      by blast
    ultimately have ¬ consistent H
      using inconsistent_parts[where ps=[]] by simp
    then show False
      using consistent H ..
  qed
next
  fix p q
  assume *: (p  q)  H
  show p  H  q  H
  proof safe
    assume q  H
    then obtain Hq' where Hq': q # Hq'   set Hq'  H
      using assms inconsistent_head by metis

    assume p  H
    then have (¬ p)  H
      using assms maximal_exactly_one by blast
    then obtain Hp' where Hp': (¬ p) # Hp'   set Hp'  H
      using assms inconsistent_head by metis

    let ?H' = Hp' @ Hq'
    have H': set ?H' = set Hp'  set Hq'
      by simp
    then have set Hp'  set ?H' and set Hq'  set ?H'
      by blast+
    then have (¬ p) # ?H'   and q # ?H'  
      using Hp'(1) Hq'(1) deduct imply_weaken by metis+
    then have (p  q) # ?H'  
      using Boole imply_Cons imply_head MP' cut by metis
    moreover have set ((p  q) # ?H')  H
      using q  H *(1) H' Hp'(2) Hq'(2) by auto
    ultimately show False
      using assms unfolding consistent_def by blast
  qed
next
  fix p q
  assume *: (p  q)  H
  show p  H  q  H
  proof (safe, rule ccontr)
    assume p  H
    then obtain H' where S': p # H'   set H'  H
      using assms inconsistent_head by metis
    moreover have (¬ (p  q)) # H'  p
      by auto
    ultimately have (¬ (p  q)) # H'  
      by blast
    moreover have set ((¬ (p  q)) # H')  H
      using *(1) S'(2) assms maximal_exactly_one by auto
    ultimately show False
      using assms unfolding consistent_def by blast
  next
    assume q  H
    then have (¬ q)  H
      using assms maximal_exactly_one by blast
    then obtain H' where H': (¬ q) # H'   set H'  H
      using assms inconsistent_head by metis
    moreover have (¬ (p  q)) # H'  ¬ q
      by auto
    ultimately have (¬ (p  q)) # H'  
      by blast
    moreover have set ((¬ (p  q)) # H')  H
      using *(1) H'(2) assms maximal_exactly_one by auto
    ultimately show False
      using assms unfolding consistent_def by blast
  qed
next
  fix p
  assume p  H
  then show t. pt/0  H
    using assms consistent_add_instance unfolding maximal_def by blast
next
  fix p
  assume p  H
  then show n. p#n/0  H
    using assms maximal_exactly_one unfolding saturated_def by fast
qed

section ‹Countable Formulas›

instance tm :: (countable) countable
  by countable_datatype

instance fm :: (countable, countable) countable
  by countable_datatype

section ‹Completeness›

theorem strong_completeness:
  fixes p :: ('f :: countable, 'p :: countable) fm
  assumes (E :: _  'f tm) F G. Ball X E, F, G  E, F, G p
    and finite (vars X)
  shows ps. set ps  X  ps  p
proof (rule ccontr)
  assume ps. set ps  X  ps  p
  then have *: ps. set ps  X  (¬ p) # ps  
    using Boole by blast

  let ?S = {¬ p}  X
  let ?H = Extend ?S from_nat

  have consistent ?S
    using * by (metis consistent_def imply_Cons inconsistent_fm)
  moreover have finite (vars ?S)
    using assms by simp
  ultimately have consistent ?H and maximal ?H
    using assms consistent_Extend maximal_Extend surj_from_nat by blast+
  moreover from this have saturated ?H
    using saturated_Extend by fastforce
  ultimately have Hintikka ?H
    using assms Hintikka_Extend by blast

  have ?H p if p  ?S for p
    using that Extend_subset Hintikka_model Hintikka ?H by blast
  then have ?H (¬ p) and q  X. ?H q
    by fastforce+
  moreover from this have ?H p
    using assms(1) by blast
  ultimately show False
    by simp
qed

theorem completeness:
  fixes p :: ('f :: countable, 'p :: countable) fm
  assumes (E :: _  'f tm) F G. E, F, G p
  shows  p
  using assms strong_completeness[where X={}] by simp

corollary
  fixes p :: (unit, unit) fm
  assumes (E :: nat  unit tm) F G. E, F, G p
  shows  p
  using completeness assms .

section ‹Main Result›

abbreviation valid :: (nat, nat) fm  bool where
  valid p  (E :: nat  nat tm) F G. E, F, G p

theorem main: valid p  ( p)
  using completeness soundness by blast

end