Theory Calculi_And_Annotations

(* Title:        Formalizing an abstract calculus based on splitting in a modular way
 * Authors:      Sophie Tourret <stourret at mpi-inf.mpg.de>, 2020-2025
 *               Florent Krasnopol <florent.krasnopol at ens-paris-saclay.fr>, 2022
 *               Ghilain Bergeron <ghilain.bergeron at inria.fr>, 2023 *)


theory Calculi_And_Annotations
  imports Disjunctive_Consequence_Relations
begin


section ‹Calculi and Derivations›

context
begin

no_notation Extended.extended.Pinf ()

typedef 'a infinite_llist = { l :: 'a llist. llength l =  }
  morphisms to_llist Abs_infinite_llist
  using llength_inf_llist
  by blast

setup_lifting type_definition_infinite_llist

lift_definition llmap :: ('a  'b)  'a infinite_llist  'b infinite_llist is lmap
  by auto

lift_definition llnth :: 'a infinite_llist  nat  'a is lnth .

lift_definition Liminf_infinite_llist :: 'a set infinite_llist  'a set is Liminf_llist .

lift_definition Limsup_infinite_llist :: 'a set infinite_llist  'a set is Limsup_llist .

lift_definition Sup_infinite_llist :: 'a set infinite_llist  'a set is Sup_llist .

lift_definition llhd :: 'a infinite_llist  'a is lhd .

lemma llength_of_to_llist_is_infinite: llength (to_llist L) = 
  using to_llist
  by auto

end (* unnamed context *)

locale sound_inference_system =
  inference_system Inf + sound_cons: consequence_relation bot entails_sound
  for
    Inf :: "'f inference set" and
    bot :: "'f" and
    entails_sound :: "'f set  'f set  bool" (infix "⊨s" 50)
  + assumes
    sound: "ι  Inf  set (prems_of ι) ⊨s {concl_of ι}"

no_notation IArray.sub (infixl "!!" 100)
  
definition is_derivation :: "('f set  'f set  bool)  ('f set infinite_llist)  bool" where
  "is_derivation R Ns  i. R (llnth Ns i) (llnth Ns (Suc i))"
  
definition terminates :: "'f set infinite_llist  bool" where
  "terminates Ns  i. j>i. llnth Ns j = llnth Ns i"

abbreviation lim_inf  Liminf_infinite_llist

abbreviation limit :: "'f set infinite_llist  'f set" where "limit Ns  lim_inf Ns"

abbreviation lim_sup :: 'f set infinite_llist  'f set where
  lim_sup Ns  Limsup_infinite_llist Ns

locale calculus = inference_system Inf + consequence_relation bot entails
  for
    bot :: "'f" and
    Inf :: 'f inference set and
    entails :: "'f set  'f set  bool" (infix "" 50)
  + fixes
    RedI :: "'f set  'f inference set" and
    RedF :: "'f set  'f set"
  assumes
    Red_I_to_Inf: "RedI N  Inf" and
    Red_F_Bot: "N  {bot}  N - RedF N  {bot}" and
    Red_F_of_subset: "N  N'  RedF N  RedF N'" and
    Red_I_of_subset: "N  N'  RedI N  RedI N'" and
    Red_F_of_Red_F_subset: "N'  RedF N  RedF N  RedF (N - N')" and
    Red_I_of_Red_F_subset: "N'  RedF N  RedI N  RedI (N - N')" and
    Red_I_of_Inf_to_N: "ι  Inf  concl_of ι  N  ι  RedI N"
begin

definition saturated :: "'f set  bool" where
  "saturated N  Inf_from N  RedI N"
  
definition RedI_strict :: "'f set  'f inference set" where
  "RedI_strict N = {ι. ι  RedI N  (ι  Inf  bot  N)}"
  
definition RedF_strict :: "'f set  'f set" where
  "RedF_strict N = {C. C  RedF N  (bot  N  C  bot)}"
  
(* This proof helped detect a lack of precision in rmk 3 (missing restriction in the hypotheses *)
lemma strict_calc_if_nobot:
  "N. bot  RedF N  calculus bot Inf entails RedI_strict RedF_strict"
proof
  fix N
  show RedI_strict N  Inf unfolding RedI_strict_def using Red_I_to_Inf by blast
next
  fix N
  assume
    bot_notin: "N. bot  RedF N" and
    entails_bot: N  {bot}
  show N - RedF_strict N  {bot}
  proof (cases "bot  N")
    assume bot_in: "bot  N"
    have bot  RedF N using bot_notin by blast
    then have bot  RedF_strict N unfolding RedF_strict_def by blast 
    then have RedF_strict N = UNIV - {bot}
      unfolding RedF_strict_def using bot_in by blast
    then have N - RedF_strict N = {bot} using bot_in by blast
    then show N - RedF_strict N  {bot} using entails_reflexive[of bot] by simp
  next
    assume bot  N
    then have RedF_strict N = RedF N unfolding RedF_strict_def by blast
    then show N - RedF_strict N  {bot} using Red_F_Bot[OF entails_bot] by simp
  qed
next
  fix N N' :: "'f set"
  assume N  N'
  then show RedF_strict N  RedF_strict N'
    unfolding RedF_strict_def using Red_F_of_subset by blast
next
  fix N N' :: "'f set"
  assume N  N'
  then show RedI_strict N  RedI_strict N'
    unfolding RedI_strict_def using Red_I_of_subset by blast
next
  fix N' N
  assume
    bot_notin: "N. bot  RedF N" and
    subs_red: "N'  RedF_strict N"
  have bot  RedF_strict N
    using bot_notin unfolding RedF_strict_def by blast
  then have nbot_in: bot  N' using subs_red by blast 
  show RedF_strict N  RedF_strict (N - N')
  proof (cases "bot  N")
    case True
    then have bot_in: "bot  N - N'" using nbot_in by blast
    then show ?thesis unfolding RedF_strict_def using bot_notin by force
  next
    case False
    then have eq_red: "RedF_strict N = RedF N" unfolding RedF_strict_def by simp
    then have "N'  RedF N" using subs_red by simp
    then have "RedF N  RedF (N - N')" using Red_F_of_Red_F_subset by simp
    then show ?thesis using eq_red RedF_strict_def by blast 
  qed
next
  fix N' N
  assume
    "N. bot  RedF N" and
    subs_red: "N'  RedF_strict N"
  then have bot_notin: "bot  N'" unfolding RedF_strict_def by blast 
  then show "RedI_strict N  RedI_strict (N - N')"
  proof (cases "bot  N")
    case True
    then show ?thesis
      unfolding RedI_strict_def using bot_notin Red_I_to_Inf by fastforce 
  next
    case False
    then show ?thesis
      using bot_notin Red_I_to_Inf subs_red Red_I_of_Red_F_subset 
      unfolding RedI_strict_def RedF_strict_def by simp
  qed
next
  fix ι N
  assume "ι  Inf"
  then show "concl_of ι  N  ι  RedI_strict N"
    unfolding RedI_strict_def using Red_I_of_Inf_to_N Red_I_to_Inf by simp
qed

definition weakly_fair :: "'f set infinite_llist  bool" where
  weakly_fair Ns  Inf_from (Liminf_infinite_llist Ns)  Sup_infinite_llist (llmap RedI Ns)

abbreviation fair :: "'f set infinite_llist  bool" where "fair N  weakly_fair N"

definition derive :: "'f set  'f set  bool" (infix "" 50) where
  "M  N  (M - N  RedF N)"

(* for reference, the definition used in the saturation framework *)
(* inductive "derive" :: "'f set ⇒ 'f set ⇒ bool" (infix "⊳" 50) where
     derive: "M - N ⊆ RedF N ⟹ M ⊳ N" *)

lemma derive_refl: "M  M" unfolding derive_def by simp

lemma deriv_red_in: M  N  RedF M  N  RedF N
proof -
  fix M N
  assume deriv: M  N
  then have M  N  RedF N
    unfolding derive_def by blast 
  then have red_m_in: RedF M  RedF (N  RedF N)
    using Red_F_of_subset by blast 
  have RedF (N  RedF N)  RedF (N  RedF N - (RedF N - N))
    using Red_F_of_Red_F_subset[of "RedF N - N" "N  RedF N"]
      Red_F_of_subset[of "N" "N  RedF N"] by fast
  then have RedF (N  RedF N)  RedF N
    by (metis Diff_subset_conv Red_F_of_subset Un_Diff_cancel lfp.leq_trans subset_refl sup.commute)
  then show RedF M  N  RedF N using red_m_in by blast
qed

lemma derive_trans: "M  N  N  N'  M  N'" 
  using deriv_red_in by (smt Diff_subset_conv derive_def subset_trans sup.absorb_iff2)

end
  
locale sound_calculus = sound_inference_system Inf bot entails_sound +
  consequence_relation bot entails
  for
    bot :: "'f" and
    Inf :: 'f inference set and
    entails :: "'f set  'f set  bool" (infix "" 50) and
    entails_sound :: "'f set  'f set  bool" (infix "⊨s" 50)
    + fixes
    RedI :: "'f set  'f inference set" and
    RedF :: "'f set  'f set"
    assumes
      Red_I_to_Inf: "RedI N  Inf" and
      Red_F_Bot: "N  {bot}  N - RedF N  {bot}" and
      Red_F_of_subset: "N  N'  RedF N  RedF N'" and
      Red_I_of_subset: "N  N'  RedI N  RedI N'" and
      Red_F_of_Red_F_subset: "N'  RedF N  RedF N  RedF (N - N')" and
      Red_I_of_Red_F_subset: "N'  RedF N  RedI N  RedI (N - N')" and
      Red_I_of_Inf_to_N: "ι  Inf  concl_of ι  N  ι  RedI N"
begin

sublocale calculus bot Inf entails
  by (simp add: calculus.intro calculus_axioms.intro Red_F_Bot
    Red_F_of_Red_F_subset Red_F_of_subset Red_I_of_Inf_to_N Red_I_of_Red_F_subset Red_I_of_subset
    Red_I_to_Inf consequence_relation_axioms)
end
      
locale statically_complete_calculus = calculus +
  assumes statically_complete: "saturated N  N  {bot}  bot  N"
begin

lemma inf_from_subs: "M  N  Inf_from M  Inf_from N"
  unfolding Inf_from_def by blast
    
    (* Splitting report Lemma 2 *)
lemma nobot_in_Red: bot  RedF N
proof -
  have UNIV  {bot}
    using entails_reflexive[of bot] entails_subsets[of "{bot}" UNIV "{bot}" "{bot}"] by fast
  then have non_red_entails_bot: UNIV - (RedF UNIV)  {bot} using Red_F_Bot[of UNIV] by simp
  have Inf_from UNIV  RedI UNIV
    unfolding Inf_from_def using Red_I_of_Inf_to_N[of _ UNIV] by blast
  then have sat_non_red: saturated (UNIV - RedF UNIV)
    unfolding saturated_def Inf_from_def using Red_I_of_Red_F_subset[of "RedF UNIV" UNIV] by blast 
  have bot  RedF UNIV 
    using statically_complete[OF sat_non_red non_red_entails_bot] by fast
  then show ?thesis using Red_F_of_subset[of _ UNIV] by auto
qed
  
  (* Splitting report Remark 3 *)
interpretation strict_calculus:
  statically_complete_calculus bot Inf entails RedI_strict RedF_strict
proof -
  interpret strict_calc: calculus bot Inf entails RedI_strict RedF_strict
  using strict_calc_if_nobot nobot_in_Red by blast 
    (* next property is not needed for the proof, but it is one of the claims from Rmk 3
    that must be verified *)
  have saturated N  strict_calc.saturated N
    unfolding saturated_def strict_calc.saturated_def RedI_strict_def by blast
  have strict_calc.saturated N  N  {bot}  bot  N for N
  proof -
    assume
      strict_sat: "strict_calc.saturated N" and
      entails_bot: "N  {bot}"
    have bot  N  RedI_strict N = RedI N unfolding RedI_strict_def by simp
    then have bot  N  saturated N
      unfolding saturated_def using strict_sat by (simp add: strict_calc.saturated_def) 
    then have bot  N  bot  N
      using statically_complete[OF _ entails_bot] by simp
    then show bot  N by auto 
  qed
  then show statically_complete_calculus bot Inf entails RedI_strict RedF_strict
    unfolding statically_complete_calculus_def statically_complete_calculus_axioms_def
    using strict_calc.calculus_axioms by blast
qed

end

locale dynamically_complete_calculus = calculus +
  assumes dynamically_complete:
    is_derivation (⊳) Ns  fair Ns  llhd Ns  {bot}  i. bot  llnth Ns i


(*******************************************)
section ‹Annotated Formulas and Consequence Relations›

datatype ('f, 'v::countable) AF = Pair (F_of: "'f") (A_of: "'v sign fset")

definition is_interpretation :: "'v sign set  bool" where
  is_interpretation J = (v1J. (v2J. (to_V v1 = to_V v2  v1 = v2)))
  
typedef 'v propositional_interpretation = "{J :: 'v sign set. is_interpretation J}"
proof
  show {}  {J. is_interpretation J} unfolding is_interpretation_def by blast 
qed
  
abbreviation "interp_of  Abs_propositional_interpretation"
abbreviation "strip  Rep_propositional_interpretation"

setup_lifting type_definition_propositional_interpretation

lift_definition belong_to :: "'v sign  'v propositional_interpretation  bool" (infix "J" 90)
  is "(∈)::('v sign  'v sign set  bool)" .

definition total :: "'v propositional_interpretation  bool" where
  total J  (v. (vJ. vJ J J  to_V vJ = v))
  
typedef 'v total_interpretation = "{J :: 'v propositional_interpretation. total J}"
proof
  show interp_of (Pos ` (UNIV :: 'v set))  {J. total J}
    unfolding total_def   
  proof 
    show "v. vJ. vJ J interp_of (range Pos)  to_V vJ = v"
    proof
      fix v
      have "Pos v J interp_of (range Pos)  to_V (Pos v) = v"
        by (simp add: Abs_propositional_interpretation_inverse belong_to.rep_eq is_interpretation_def)
      then show "vJ. vJ J interp_of (range Pos)  to_V vJ = v" by blast
    qed
  qed
qed

abbreviation "total_interp_of  (λx. Abs_total_interpretation (interp_of x))"
abbreviation "total_strip  (λx. strip (Rep_total_interpretation x))"

lemma neg_notin_total_strip [simp]: (neg a  total_strip J) = (a  total_strip J)
proof
  assume neg_a_notin: neg a  total_strip J
  have b. to_V a = to_V b  b  total_strip J
    by (metis Rep_total_interpretation belong_to.rep_eq mem_Collect_eq total_def)
  then show a  total_strip J
    using neg_a_notin by (metis neg.simps to_V.elims)
next
  assume a_in: a  total_strip J
  then have b. to_V a = to_V b  b  total_strip J
    by (metis Rep_propositional_interpretation is_interpretation_def mem_Collect_eq sign.simps(4)
        to_V.simps)
  then show neg a  total_strip J
    using a_in by (metis neg.simps to_V.elims)
qed

lemma neg_in_total_strip [simp]: (neg a  total_strip J) = (a  total_strip J)
proof
  assume neg_a_notin: neg a  total_strip J
  have b. to_V a = to_V b  b  total_strip J
   by (metis Rep_propositional_interpretation is_interpretation_def mem_Collect_eq sign.simps(4)
        to_V.simps)
  then show a  total_strip J
    using neg_a_notin by (metis neg.simps to_V.elims)
next
  assume a_in: a  total_strip J
  then have b. to_V a = to_V b  b  total_strip J
    by (metis Rep_total_interpretation belong_to.rep_eq mem_Collect_eq total_def)
  then show neg a  total_strip J
    using a_in by (metis neg.simps to_V.elims)
qed

setup_lifting type_definition_total_interpretation

lift_definition belong_to_total :: "'v sign  'v total_interpretation  bool" (infix "t" 90)
  is "(∈J)::('v sign  'v propositional_interpretation  bool)" .

lemma in_total_to_strip [simp]: a t J  a  total_strip J
  unfolding belong_to_total_def belong_to_def by simp

lemma neg_prop_interp: (v::'v sign) J J  ¬ ((neg v) J J)
proof transfer
  fix v J
  assume
    j_is: is_interpretation (J:: 'v sign set) and
    v_in: v  J
  then show ¬ (neg v)  J
  proof (cases v)
    case (Pos C)
    then show ?thesis
      using is_Pos.simps
      by (metis is_interpretation_def j_is neg.simps(1) to_V.simps v_in)
  next
    case (Neg C)
    then show ?thesis
      using j_is v_in
      using is_interpretation_def by fastforce
  qed
qed

lemma neg_total_interp: (v::'v sign) t J  ¬ ((neg v) t J)
proof transfer
  fix v J
  assume v_in: v J (J :: 'v propositional_interpretation)
  show ¬ neg v J J
    using neg_prop_interp[OF v_in] by simp
qed

lemma neg_notin_total_interp: ¬ (v t J)  ((neg v) t J)
proof transfer
  fix v::"'v sign" and J
  assume 
    tot: total J and
    not_in: ¬ v J J
  show neg v J J
    using tot not_in unfolding total_def
    by (metis belong_to_total.abs_eq eq_onp_def in_total_to_strip neg_in_total_strip tot)
qed

definition to_AF :: "'f  ('f, 'v::countable) AF" where
  to_AF C = Pair C {||}

lemma F_of_to_AF: F_of (to_AF 𝒞) = 𝒞
  unfolding to_AF_def
  by auto

lemma A_of_to_AF: A_of (to_AF 𝒞) = {||}
  unfolding to_AF_def
  by auto

lemma F_of_circ_to_AF_is_id [simp]: F_of  to_AF = id
  by (fastforce simp: F_of_to_AF)

lemma A_of_circ_to_AF_is_empty_set [simp]: A_of  to_AF = (λ _. {||})
  by (fastforce simp: A_of_to_AF) 

lemma F_of_propositional_clauses [simp]:
  ( x  set 𝒩. F_of x = bot)  map F_of 𝒩 = map (λ _. bot) 𝒩
  using map_eq_conv
  by blast

lemma F_of_Pair [simp]: F_of  (λ(x, y). AF.Pair x y) = (λ(x, y). x)
  by (smt (verit, ccfv_SIG) AF.sel(1) comp_apply cond_case_prod_eta old.prod.case)

lemma A_of_Pair [simp]: A_of  (λ(x, y). AF.Pair x y) = (λ(x, y). y)
  by fastforce

lemma map_A_of_map2_Pair: length A = length B  map A_of (map2 AF.Pair A B) = B
proof -
  assume length A = length B
  then have map2 (λ x y. y) A B = B
    by (metis map_eq_conv map_snd_zip snd_def)
  then show ?thesis
    by auto 
qed  

definition Neg_set :: "'v sign set  'v sign set" ("_" 55) where
  V  {neg v |v. v  V}

definition F_of_Inf :: "(('f, 'v::countable) AF) inference  'f inference" where
  F_of_Inf ιAF = (Infer (map F_of (prems_of ιAF)) (F_of (concl_of ιAF)))

section ‹Lifting Calculi to Add Annotations›

locale calculus_with_annotated_consrel = sound_calculus bot Inf entails entails_sound RedI RedF
  for
    bot :: "'f" and
    Inf :: 'f inference set and
    entails :: "'f set  'f set  bool" (infix "" 50) and
    entails_sound :: "'f set  'f set  bool" (infix "⊨s" 50) and
    RedI :: "'f set  'f inference set" and
    RedF :: "'f set  'f set"
  + fixes
    fml :: 'v :: countable  'f and 
    asn :: 'f sign  'v sign set
  assumes
    fml_entails_C:  a  asn C. sound_cons.entails_neg {map_sign fml a} {C} and
    C_entails_fml:  a  asn C. sound_cons.entails_neg {C} {map_sign fml a} and
    asn_not_empty: asn C  {}
begin

notation sound_cons.entails_neg (infix ⊨s 50)

lemma equi_entails_if_a_in_asns: a  asn C  a  asn D  {C} ⊨s {D}  {D} ⊨s {C}
  by (smt (verit) C_entails_fml Un_commute consequence_relation.entails_cut fml_entails_C
    sound_cons.ext_cons_rel sup_bot_left)

lemma equi_entails_if_neg_a_in_asn:
  a  asn C  neg a  asn D  {C} ⊨s {neg D}  {neg D} ⊨s {C}
proof (intro conjI)
  assume a_in_asn_C: a  asn C and
         neg_a_in_asn_D: neg a  asn D

  have fml_neg_is_neg_fml: map_sign fml (neg x) = neg (map_sign fml x) for x
    by (smt (verit, ccfv_threshold) neg.simps(1) neg_neg_A_is_A sign.simps(10) sign.simps(9)
        to_V.elims)  

  have {C} ⊨s {map_sign fml a}
    using a_in_asn_C C_entails_fml
    by blast
  then have {C} ⊨s {neg D, map_sign fml a}
    by (smt (verit, best) Un_upper2 consequence_relation.entails_subsets insert_is_Un
        sound_cons.ext_cons_rel sup_ge1)
  moreover have {D} ⊨s {map_sign fml (neg a)}
    using neg_a_in_asn_D C_entails_fml
    by blast
  then have {neg (neg D)} ⊨s {neg (map_sign fml a)}
    by (simp add: fml_neg_is_neg_fml)
  then have {map_sign fml a} ⊨s {neg D}
    using sound_cons.swap_neg_in_entails_neg
    by blast 
  then have {map_sign fml a, C} ⊨s {neg D}
    by (smt (verit, best) consequence_relation.entails_subsets insert_is_Un sound_cons.ext_cons_rel
        sup_ge1)
  ultimately show {C} ⊨s {neg D}
    using consequence_relation.entails_cut
    by (smt (verit, ccfv_threshold) Un_commute insert_is_Un sound_cons.ext_cons_rel sup.idem)
next
  assume a_in_asn_C: a  asn C and
         neg_a_in_asn_D: neg a  asn D

  have fml_neg_is_neg_fml: map_sign fml (neg x) = neg (map_sign fml x) for x
    by (smt (verit, ccfv_threshold) neg.simps(1) neg_neg_A_is_A sign.simps(10) sign.simps(9)
        to_V.elims)  

  have {map_sign fml a} ⊨s {C}
    using a_in_asn_C fml_entails_C
    by blast
  then have {neg D, map_sign fml a} ⊨s {C}
    by (smt (verit, best) Un_upper2 consequence_relation.entails_subsets insert_is_Un
        sound_cons.ext_cons_rel sup_ge1)
  moreover have {map_sign fml (neg a)} ⊨s {D}
    using neg_a_in_asn_D fml_entails_C
    by blast
  then have {neg (map_sign fml a)} ⊨s {neg (neg D)}
    by (simp add: fml_neg_is_neg_fml)
  then have {neg D} ⊨s {map_sign fml a}
    using sound_cons.swap_neg_in_entails_neg
    by blast
  then have {neg D} ⊨s {map_sign fml a, C}
    by (smt (verit, best) consequence_relation.entails_subsets insert_is_Un sound_cons.ext_cons_rel
        sup_ge1)
  ultimately show {neg D} ⊨s {C}
    using consequence_relation.entails_cut
    by (smt (verit, ccfv_threshold) Un_commute insert_is_Un sound_cons.ext_cons_rel sup.idem)
qed                                  

definition ιF_of :: "('f, 'v) AF inference  'f inference" where
  ιF_of ι = Infer (List.map F_of (prems_of ι)) (F_of (concl_of ι))
  
definition propositional_projection :: "('f, 'v) AF set  ('f, 'v) AF set" ("proj") where
  proj 𝒩 = {𝒞. 𝒞  𝒩  F_of 𝒞 = bot}

lemma prop_proj_in: proj 𝒩  𝒩
  unfolding propositional_projection_def by blast

definition enabled :: "('f, 'v) AF  'v total_interpretation  bool" where
  "enabled 𝒞 J  fset (A_of 𝒞)  (total_strip J)"

lemma subformula_of_enabled_formula_is_enabled: A_of 𝒞 |⊂| A_of 𝒞'  enabled 𝒞' J  enabled 𝒞 J
  unfolding enabled_def
  by (meson less_eq_fset.rep_eq pfsubset_imp_fsubset subset_trans)

lemma enabled_iff: A_of 𝒞 = A_of 𝒞'  enabled 𝒞 J  enabled 𝒞' J
  unfolding enabled_def
  by simp

definition enabled_set :: "('f, 'v) AF set  'v total_interpretation  bool" where
  enabled_set 𝒩 J = (𝒞𝒩. enabled 𝒞 J)

lemma enabled_set_singleton [simp]: enabled_set {𝒞} J  enabled 𝒞 J
  by (auto simp add: enabled_set_def)

definition enabled_inf :: "('f, 'v) AF inference  'v total_interpretation  bool" where
  enabled_inf ι J = (𝒞 set (prems_of ι). enabled 𝒞 J)
  
definition enabled_projection :: "('f, 'v) AF set  'v total_interpretation  'f set"
  (infix "projJ" 60)  where
  𝒩 projJ J = {F_of 𝒞 |𝒞. 𝒞  𝒩  enabled 𝒞 J}

lemma Union_of_enabled_projection_is_enabled_projection: ( 𝒞  𝒩. {𝒞} projJ 𝒥) = 𝒩 projJ 𝒥
  unfolding enabled_projection_def
  by blast

lemma projection_of_enabled_subset:
  fset B  total_strip J  {AF.Pair C (A |∪| B)} projJ J = {AF.Pair C A} projJ J
  unfolding enabled_projection_def enabled_def
  by auto

lemma Un_of_enabled_projection_is_enabled_projection_of_Un:
  ( x. P x) projJ J = ( x. P x projJ J)
proof (intro subset_antisym subsetI)
  fix x
  assume x  ( x. P x) projJ J
  then have  y. x = F_of y  enabled y J  y  ( x. P x)
    unfolding enabled_projection_def
    by blast
  then have  y. x = F_of y  enabled y J  ( z. y  P z)
    by blast
  then have  y.  z. x = F_of y  enabled y J  y  P z
    by blast
  then show x  ( x. P x projJ J)
    unfolding enabled_projection_def
    by blast
next
  fix x
  assume x  ( x. P x projJ J)
  then have  y. x  P y projJ J
    by blast
  then have  y.  z. x = F_of z  enabled z J  z  P y
    unfolding enabled_projection_def
    by blast
  then show x  ( x. P x) projJ J
    unfolding enabled_projection_def
    by blast
qed

lemma enabled_projection_of_Int_is_Int_of_enabled_projection:
  x  ( S) projJ J  x   { x projJ J | x. x  S }
  unfolding enabled_projection_def
  by blast

definition enabled_projection_Inf :: "('f, 'v) AF inference set  'v total_interpretation 
  'f inference set" (infix "ιprojJ" 60) where
  I ιprojJ J = {ιF_of ι | ι. ι  I  enabled_inf ι J}

fun fml_ext :: "'v sign  'f sign" where
  "fml_ext (Pos v) = Pos (fml v)" |
  "fml_ext (Neg v) = Neg (fml v)"

lemma fml_ext_is_mapping: fml_ext v = map_sign fml v
  by (metis fml_ext.cases fml_ext.simps(1) fml_ext.simps(2) sign.simps(10) sign.simps(9)) 

lemma fml_ext_preserves_sign: "is_Pos v  is_Pos (fml_ext v)"
  by (induct v, auto)

lemma to_V_fml_ext [simp]: to_V (fml_ext v) = fml (to_V v)
  by (induct v, auto) 

lemma fml_ext_preserves_val: to_V v1 = to_V v2  to_V (fml_ext v1) = to_V (fml_ext v2)
  by simp
 
definition sound_consistent :: "'v total_interpretation  bool" where
  sound_consistent J  ¬ (sound_cons.entails_neg (fml_ext ` (total_strip J)) {Pos bot})
  
definition propositional_model :: "'v total_interpretation  ('f, 'v) AF set  bool"
  (infix "p" 50) where
  J p 𝒩  bot  ((proj 𝒩) projJ J)

lemma J p {} 
  unfolding propositional_model_def enabled_projection_def propositional_projection_def by blast

text ‹The definition below is essentially the same as the one above since term(proj 𝒩) projJ J› is 
either empty or contains only bot›
definition propositional_model2 :: "'v total_interpretation  ('f, 'v) AF set  bool"
  (infix "p2" 50) where
  J p2 𝒩  ({} = ((proj 𝒩) projJ J))

lemma subset_model_p2: 𝒩'  𝒩  J p2 𝒩  J p2 𝒩'
  by (simp add: enabled_projection_def propositional_model2_def propositional_projection_def 
      subset_eq)

lemma subset_not_model: ¬ J p2 𝒩  𝒩 = 𝒩1  𝒩2  J p2 𝒩1  ¬ J p2 𝒩2
  unfolding propositional_model2_def propositional_projection_def enabled_projection_def by blast

lemma supset_not_model_p2: 𝒩'  𝒩  ¬ J p2 𝒩'  ¬ J p2 𝒩
  using subset_model_p2 by blast

fun sign_to_atomic_formula :: "'v sign  'v formula" where
  sign_to_atomic_formula (Pos v) = Atom v |
  sign_to_atomic_formula (Neg v) = Not (Atom v)

definition sign_set_to_formula_set :: "'v sign set  'v formula set" where
  sign_set_to_formula_set A = sign_to_atomic_formula ` A

lemma form_shape_sign_set: fsign_set_to_formula_set A. v. f = Atom v  f = Not (Atom v)
  unfolding sign_set_to_formula_set_def
  by (metis image_iff sign_to_atomic_formula.elims)

definition AF_to_formula_set :: "('f, 'v) AF  'v formula set" where
  (* /!\ this formula set is to be understood as a disjunction *)
  AF_to_formula_set 𝒞 = sign_set_to_formula_set (neg ` fset (A_of 𝒞))

definition AF_to_formula :: "('f, 'v) AF  'v formula" where
  AF_to_formula 𝒞 = BigOr (map sign_to_atomic_formula (map neg (list_of_fset (A_of 𝒞))))

lemma form_shape_AF: fAF_to_formula_set 𝒞. v. f = Atom v  f = Not (Atom v)
  using form_shape_sign_set unfolding AF_to_formula_set_def by simp

definition AF_proj_to_formula_set_set :: "('f, 'v) AF set  'v formula set set" where
  (* /!\ formula set set represents here a conjuction of disjunctions *)
  AF_proj_to_formula_set_set 𝒩 = AF_to_formula_set ` (proj 𝒩)

definition AF_proj_to_formula_set :: "('f, 'v) AF set  'v formula set" where
  AF_proj_to_formula_set 𝒩 = AF_to_formula ` (proj 𝒩)

definition AF_assertions_to_formula :: "('f, 'v) AF  'v formula" where
  AF_assertions_to_formula 𝒞 = BigAnd (map sign_to_atomic_formula (list_of_fset (A_of 𝒞)))

definition AF_assertions_to_formula_set :: "('f, 'v) AF set  'v formula set" where
  AF_assertions_to_formula_set 𝒩 = AF_assertions_to_formula ` 𝒩

lemma F_to_𝒞_set: FAF_proj_to_formula_set_set 𝒩. 𝒞proj 𝒩. F =
  sign_to_atomic_formula ` neg ` fset (A_of 𝒞)
  unfolding AF_proj_to_formula_set_set_def AF_to_formula_set_def sign_set_to_formula_set_def
  by auto

lemma F_to_𝒞: FAF_proj_to_formula_set 𝒩. 𝒞proj 𝒩. F =
   BigOr (map sign_to_atomic_formula (map neg (list_of_fset (A_of 𝒞))))
  unfolding AF_proj_to_formula_set_def AF_to_formula_def by auto

lemma 𝒞_to_F_set: 𝒞proj 𝒩. FAF_proj_to_formula_set_set 𝒩. F =
  sign_to_atomic_formula ` neg ` fset (A_of 𝒞)
  unfolding AF_proj_to_formula_set_set_def AF_to_formula_set_def sign_set_to_formula_set_def
  by auto

lemma 𝒞_to_F: 𝒞proj 𝒩. FAF_proj_to_formula_set 𝒩. F =
  BigOr (map sign_to_atomic_formula (map neg (list_of_fset (A_of 𝒞))))
  unfolding AF_proj_to_formula_set_def AF_to_formula_def by auto

lemma form_shape_proj: f (AF_proj_to_formula_set_set 𝒩). v. f = Atom v  f = Not (Atom v)
  using form_shape_AF unfolding AF_proj_to_formula_set_set_def by simp

definition to_valuation :: "'v total_interpretation  'v valuation" where
  to_valuation J = (λa. Pos a t J)

lemma val_strip_pos: to_valuation J a  Pos a  total_strip J
  unfolding to_valuation_def belong_to_total_def belong_to_def by simp

lemma val_strip_neg: (¬ to_valuation J a) = (Neg a  total_strip J)
proof -
  have (¬ to_valuation J a) = (¬ Pos a  total_strip J)
    using val_strip_pos by simp
  also have (¬ Pos a  total_strip J) = (Neg a  total_strip J)
  proof
    fix a J
    assume not_pos: Pos (a::'v)  total_strip J
    have is_interpretation (total_strip J)
      using Rep_propositional_interpretation by blast 
    then show Neg a  total_strip J 
      unfolding is_interpretation_def using total_def not_pos
      by (metis Rep_total_interpretation belong_to.rep_eq mem_Collect_eq to_V.elims)
  next
    assume neg: Neg a  total_strip J
    have is_interpretation (total_strip J)
      using Rep_propositional_interpretation by blast
    then show Pos a  total_strip J
      unfolding is_interpretation_def using neg
    by (metis sign.distinct(1) to_V.simps(1) to_V.simps(2))
  qed
  finally show (¬ to_valuation J a) = (Neg a  total_strip J) .
qed

lemma equiv_prop_entails: (J p 𝒩)  (J p2 𝒩)
  unfolding propositional_model_def propositional_model2_def propositional_projection_def
    enabled_projection_def
  by blast

definition propositional_model3 :: "'v total_interpretation  ('f, 'v) AF set  bool"
  (infix "p3" 50) where
  J p3 𝒩  (FAF_proj_to_formula_set_set 𝒩. fF. formula_semantics (to_valuation J) f)

(* The interest of this first semantic characterization is that it is computable, but it is not
   convenient to apply the compactness results *)
lemma equiv_prop_entail2_sema:
  (J p2 𝒩)  (J p3 𝒩)
  unfolding propositional_model3_def propositional_model2_def enabled_projection_def enabled_def
proof
  assume empty_proj: {} = {F_of 𝒞 |𝒞. 𝒞  proj 𝒩  fset (A_of 𝒞)  total_strip J}
  then have 𝒞proj 𝒩. vfset (A_of 𝒞). neg v  total_strip J 
    by (smt (verit, ccfv_SIG) empty_iff mem_Collect_eq neg.elims subsetI
        val_strip_neg val_strip_pos)
  show FAF_proj_to_formula_set_set 𝒩. fF. formula_semantics (to_valuation J) f
  proof
    fix F
    assume F_in: F  AF_proj_to_formula_set_set 𝒩
    then obtain 𝒞 where 𝒞  proj 𝒩 and F_from_𝒞: F = sign_to_atomic_formula ` neg ` fset (A_of 𝒞)
      using F_to_𝒞_set by meson
    then have vfset (A_of 𝒞). v  total_strip J
      using empty_proj by blast
    then obtain v where v_in: v  fset (A_of 𝒞) and v_notin: v  total_strip J by auto
    define f where f = sign_to_atomic_formula (neg v)
    then have formula_semantics (to_valuation J) f
      using v_notin
      by (smt (z3) belong_to.rep_eq belong_to_total.rep_eq formula_semantics.simps neg.elims
          sign_to_atomic_formula.simps to_valuation_def val_strip_neg)
    moreover have f  F
      using F_from_𝒞 v_in f_def by blast
    ultimately show fF. formula_semantics (to_valuation J) f by auto
  qed
next
  assume F_sat: FAF_proj_to_formula_set_set 𝒩. fF. formula_semantics (to_valuation J) f
  have 𝒞proj 𝒩. vfset (A_of 𝒞). neg v  total_strip J
  proof
    fix 𝒞
    assume 𝒞  proj 𝒩
    then obtain F where F  AF_proj_to_formula_set_set 𝒩 and
      F_from_𝒞: F = sign_to_atomic_formula ` neg ` fset (A_of 𝒞)
      using 𝒞_to_F_set by blast
    then have fF. formula_semantics (to_valuation J) f
      using F_sat by blast
    then obtain f where f_in: f  F and sat_f: formula_semantics (to_valuation J) f
      by blast
    then obtain v where v_is: f = sign_to_atomic_formula (neg v) and v_in: v  fset (A_of 𝒞)
      using F_from_𝒞 by blast
    then have neg v  total_strip J
      using sat_f unfolding to_valuation_def
      by (smt (z3) belong_to.rep_eq belong_to_total.rep_eq formula_semantics.simps sign.exhaust
          sign_to_atomic_formula.simps val_strip_neg val_strip_pos)
    then show vfset (A_of 𝒞). neg v  total_strip J
      using v_in by auto
  qed
  then show {} = {F_of 𝒞 |𝒞. 𝒞  proj 𝒩  fset (A_of 𝒞)  total_strip J}
    by (smt (verit, ccfv_threshold) empty_Collect_eq is_Pos.cases neg.simps(1) neg.simps(2) subsetD
        val_strip_neg val_strip_pos)
qed

(* this characterization can be used to apply the compactness from Michaelis & Nipkow but it uses
   something that can't be computed (SOME) *)
lemma equiv_prop_entail2_sema2:
  (J p2 𝒩)  (FAF_proj_to_formula_set 𝒩. formula_semantics (to_valuation J) F)
  unfolding propositional_model2_def enabled_projection_def enabled_def
proof
  assume empty_proj: {} = {F_of 𝒞 |𝒞. 𝒞  proj 𝒩  fset (A_of 𝒞)  total_strip J}
  show FAF_proj_to_formula_set 𝒩. formula_semantics (to_valuation J) F
  proof
    fix F
    assume F_in: F  AF_proj_to_formula_set 𝒩
    then obtain 𝒞 where 𝒞  proj 𝒩 and 
      F_from_𝒞: F = BigOr (map sign_to_atomic_formula (map neg (list_of_fset (A_of 𝒞))))
      using F_to_𝒞 by meson
    then have vfset (A_of 𝒞). v  total_strip J
      using empty_proj by blast
    then obtain v where v_in: v  fset (A_of 𝒞) and v_notin: v  total_strip J by auto
    define f where f = sign_to_atomic_formula (neg v)
    then have formula_semantics (to_valuation J) f
      using v_notin
      by (smt (z3) belong_to.rep_eq belong_to_total.rep_eq formula_semantics.simps neg.elims
          sign_to_atomic_formula.simps to_valuation_def val_strip_neg)
    moreover have f  set (map sign_to_atomic_formula (map neg (list_of_fset (A_of 𝒞))))
      unfolding f_def using fset_map2[OF v_in, of sign_to_atomic_formula neg] .
    ultimately have fset (map sign_to_atomic_formula (map neg (list_of_fset (A_of 𝒞)))).
     formula_semantics (to_valuation J) f
      by blast
    then show formula_semantics (to_valuation J) F
      using BigOr_semantics[of "to_valuation J"
          "map sign_to_atomic_formula (map neg (list_of_fset (A_of 𝒞)))"] F_from_𝒞
      by meson
    qed
next
  assume F_sat: FAF_proj_to_formula_set 𝒩. formula_semantics (to_valuation J) F
  have 𝒞proj 𝒩. vfset (A_of 𝒞). neg v  total_strip J
  proof
    fix 𝒞
    assume 𝒞_in: 𝒞  proj 𝒩
    define F where F = AF_to_formula 𝒞
    then have F  AF_proj_to_formula_set 𝒩
      unfolding AF_proj_to_formula_set_def using 𝒞_in by blast
    then have formula_semantics (to_valuation J) F using F_sat by blast
    then have fset (map sign_to_atomic_formula (map neg (list_of_fset (A_of 𝒞)))).
      formula_semantics (to_valuation J) f
      using BigOr_semantics[of "to_valuation J"] unfolding F_def AF_to_formula_def by simp
    then obtain f where 
      f_in: f  set (map sign_to_atomic_formula (map neg (list_of_fset (A_of 𝒞))))
      and val_f: formula_semantics (to_valuation J) f by blast
    obtain v where v_in: v  fset (A_of 𝒞) and f_is: f = sign_to_atomic_formula (neg v)
      using f_in unfolding list_of_fset_def
      by (smt (z3) exists_fset_of_list fset_of_list.rep_eq image_iff list.set_map someI)
    have neg v  total_strip J
      using f_is val_f unfolding to_valuation_def
      by (metis (mono_tags, lifting) belong_to.rep_eq belong_to_total.rep_eq 
          formula_semantics.simps(1) formula_semantics.simps(3) sign_to_atomic_formula.cases
          sign_to_atomic_formula.simps(1) sign_to_atomic_formula.simps(2) val_f val_strip_neg)
    then show vfset (A_of 𝒞). neg v  total_strip J
      using v_in by blast
  qed
  then show {} = {F_of 𝒞 |𝒞. 𝒞  proj 𝒩  fset (A_of 𝒞)  total_strip J}
    by (smt (verit, ccfv_threshold) empty_Collect_eq is_Pos.cases neg.simps(1) neg.simps(2) subsetD
        val_strip_neg val_strip_pos)
qed

lemma equiv_prop_entail_sema:
  (J p 𝒩)  (J p3 𝒩)
  using equiv_prop_entails equiv_prop_entail2_sema by presburger


lemma f ` fset A = set (map f (list_of_fset A))
proof
  show f ` fset A  set (map f (list_of_fset A))
  proof
    fix v
    assume v_in: v  f ` fset A
    then obtain a where "a |∈| A" "f a = v"
     by blast 
    then show v  set (map f (list_of_fset A))
      unfolding list_of_fset_def
      by (metis fset_map2 list_of_fset_def map_ident)
  qed
next
  show set (map f (list_of_fset A))  f ` fset A
  proof
    fix v
    assume v  set (map f (list_of_fset A))
    then obtain a where "a |∈| A" "f a = v"
      unfolding list_of_fset_def
      by (metis (mono_tags, lifting) exists_fset_of_list fimage.rep_eq fimageE fset_of_list.rep_eq 
          set_map someI_ex)
    then show v  f ` fset A
      by blast
  qed
qed

lemma equiv_prop_sema1_sema2:
  (J p3 𝒩) 
   (FAF_proj_to_formula_set 𝒩. formula_semantics (to_valuation J) F)
  using equiv_prop_entail2_sema2 equiv_prop_entail2_sema
  unfolding propositional_model3_def by auto


lemma equiv_enabled_assertions_sema:
  (enabled_set 𝒩 J)  (FAF_assertions_to_formula_set 𝒩. formula_semantics (to_valuation J) F)
  unfolding enabled_projection_def enabled_def enabled_set_def
proof
  assume enab_N: 𝒞𝒩. fset (A_of 𝒞)  total_strip J 
  show FAF_assertions_to_formula_set 𝒩. formula_semantics (to_valuation J) F
  proof
    fix F
    assume F_in: F  AF_assertions_to_formula_set 𝒩
    then obtain 𝒞 where 𝒞_in: 𝒞  𝒩 and 
      F_from_𝒞: F = BigAnd (map sign_to_atomic_formula (list_of_fset (A_of 𝒞)))
      unfolding AF_assertions_to_formula_def AF_assertions_to_formula_set_def by auto
    have fset (map sign_to_atomic_formula (list_of_fset (A_of 𝒞))).
      formula_semantics (to_valuation J) f
    proof
      fix f
      assume f_in: f  set (map sign_to_atomic_formula (list_of_fset (A_of 𝒞)))
      define L where L = (list_of_fset (A_of 𝒞))
      then obtain a v where f_is: sign_to_atomic_formula a = f and a_in: a  set L
        and v_is: to_V a = v
        using f_in by auto
      have a  fset (A_of 𝒞)
        using a_in unfolding L_def by (smt (verit, ccfv_threshold) exists_fset_of_list
            fset_of_list.rep_eq list_of_fset_def someI_ex)
      then have a_in: a  total_strip J
        using enab_N 𝒞_in by blast
      consider (Pos) "a = Pos v" | (Neg) a = Neg v
        using v_is is_Neg_to_V is_Pos_to_V by blast
      then show formula_semantics (to_valuation J) f
      proof cases
        case Pos
        then have f = Atom v using f_is by auto
        then show ?thesis
          using a_in unfolding to_valuation_def belong_to_total_def belong_to_def
          by (simp add: Pos)
      next
        case Neg
        then have f = Not (Atom v) using f_is by auto
        then show ?thesis
          using a_in Neg to_valuation_def val_strip_neg by force
      qed
    qed
    then show formula_semantics (to_valuation J) F
      using BigAnd_semantics[of "to_valuation J"
          "map sign_to_atomic_formula (list_of_fset (A_of 𝒞))"] F_from_𝒞 by blast
  qed
next
  assume F_sat: FAF_assertions_to_formula_set 𝒩. formula_semantics (to_valuation J) F
  have 𝒞𝒩. afset (A_of 𝒞). a  total_strip J
  proof clarify
    fix 𝒞 a
    assume 
      𝒞_in: 𝒞  𝒩 and
      a_in: a  fset (A_of 𝒞)
    define F where F = AF_assertions_to_formula 𝒞
    then have F  AF_assertions_to_formula_set 𝒩
      unfolding AF_assertions_to_formula_set_def using 𝒞_in by blast
    then have formula_semantics (to_valuation J) F using F_sat by blast
    then have all_f_sat: fset (map sign_to_atomic_formula (list_of_fset (A_of 𝒞))).
      formula_semantics (to_valuation J) f
      using BigAnd_semantics[of "to_valuation J"] unfolding F_def AF_assertions_to_formula_def
      by simp
    define f where f = sign_to_atomic_formula a
    then have f  set (map sign_to_atomic_formula (list_of_fset (A_of 𝒞)))
      using a_in fset_map2 by fastforce
    then have f_sat: formula_semantics (to_valuation J) f
      using all_f_sat by auto
    then show a  total_strip J
      using f_def unfolding to_valuation_def
      by (metis f_sat belong_to.rep_eq belong_to_total.rep_eq formula_semantics.simps(1)
          formula_semantics.simps(3) sign_to_atomic_formula.elims val_strip_neg)
  qed
  then show 𝒞𝒩. fset (A_of 𝒞)  total_strip J by blast
qed

definition sound_propositional_model :: "'v total_interpretation  ('f, 'v) AF set  bool"
  (infix "⊨sp" 50) where
  J ⊨sp 𝒩  (bot  ((enabled_projection (propositional_projection 𝒩) J)) 
    ¬ sound_consistent J)

definition propositionally_unsatisfiable :: "('f, 'v) AF set  bool" where
  propositionally_unsatisfiable 𝒩  J. ¬ (J p 𝒩)

lemma unsat_simp: 
  assumes 
    ¬ sat (S'  S::'v formula set)
    sat S'
     (atoms ` S')   (atoms ` S) = {}
  shows
    ¬ sat S
  unfolding sat_def
proof
  assume contra: 𝒜. FS. formula_semantics 𝒜 F
  then obtain 𝒜S where AS_is: FS. formula_semantics 𝒜S F by blast
  obtain 𝒜F where AF_is: FS'. formula_semantics 𝒜F F using assms(2) unfolding sat_def by blast
  define 𝒜 where 𝒜 = (λa. if a   (atoms ` S') then 𝒜F a else 𝒜S a)
  have FS'. formula_semantics 𝒜 F
    using AF_is relevant_atoms_same_semantics unfolding 𝒜_def
    by (smt (verit, best) UN_I)
  moreover have FS. formula_semantics 𝒜 F
    using AS_is relevant_atoms_same_semantics assms(3) unfolding 𝒜_def
    by (smt (verit, del_insts) Int_iff UN_I empty_iff)
  ultimately have F'(S'S). formula_semantics 𝒜 F' by blast
  then show False
    using assms(1) unfolding sat_def by blast
qed

lemma proj_to_form_un: AF_proj_to_formula_set (A  B) = 
  AF_proj_to_formula_set A  AF_proj_to_formula_set B
  unfolding AF_proj_to_formula_set_def propositional_projection_def by blast

lemma unsat_AF_simp: 
  assumes 
    ¬ sat (AF_proj_to_formula_set (S'  S))
    sat (AF_proj_to_formula_set S')
     (atoms ` (AF_proj_to_formula_set S'))   (atoms ` (AF_proj_to_formula_set S)) = {}
  shows
    ¬ sat (AF_proj_to_formula_set S)
  using unsat_simp assms proj_to_form_un by metis

lemma set_list_of_fset[simp]: set (list_of_fset A) = fset A
  unfolding list_of_fset_def
  by (smt (verit, del_insts) exists_fset_of_list fset_of_list.rep_eq someI_ex)

lemma vars_in_assertion: to_V ` (set (list_of_fset A)) = to_V ` (fset A)
  by simp

lemma atoms_bigor: atoms (BigOr L) =  (atoms ` (set L))
  unfolding BigOr_def by (induction L) auto

lemma atoms_neg: atoms (sign_to_atomic_formula (neg A)) = atoms (sign_to_atomic_formula A)
  by (metis formula.simps(92) neg.elims sign_to_atomic_formula.simps(1)
      sign_to_atomic_formula.simps(2))

lemma set_maps_list_of_fset: set (map sign_to_atomic_formula (map neg (list_of_fset A))) = 
  sign_to_atomic_formula ` neg ` fset A
  using set_map by auto

lemma atoms_to_V_mono: atoms (sign_to_atomic_formula A) = {to_V A}
  by (metis formula.set(1) formula.set(3) sign_to_atomic_formula.simps(1)
      sign_to_atomic_formula.simps(2) to_V.elims)

lemma atoms_to_V: (atoms ` sign_to_atomic_formula ` A) = to_V ` A
proof -
  have (atoms ` sign_to_atomic_formula ` A) = {{to_V a} |a. a  A}
    using atoms_to_V_mono by auto
  also have ... = to_V ` A
    by blast
  finally show (atoms ` sign_to_atomic_formula ` A) = to_V ` A .
qed

lemma atoms_to_V_AF: atoms (AF_to_formula (Pair C A)) = to_V ` (fset A)
proof -
  have atoms (AF_to_formula (Pair C A)) =  (atoms ` sign_to_atomic_formula ` fset A)
    using atoms_bigor set_maps_list_of_fset atoms_neg unfolding AF_to_formula_def
    by (smt (z3) AF.sel(2) image_iff subsetI subset_antisym)
  also have ... = to_V ` (fset A)
    using atoms_to_V by auto
  ultimately show atoms (AF_to_formula (Pair C A)) = to_V ` (fset A) by simp
qed

lemma atoms_to_V_A_of: atoms (AF_to_formula 𝒞) = to_V ` (fset (A_of 𝒞))
  using atoms_to_V_AF
  by (metis AF.collapse)

lemma atoms_to_V_un: (atoms ` AF_to_formula ` 𝒮) = {to_V ` fset A |A. A  A_of ` 𝒮}
proof -
  have (x  (atoms ` AF_to_formula ` 𝒮)) = (x  {to_V ` (fset A) |A. A  A_of ` 𝒮}) for x
    using atoms_to_V_A_of by blast
  then show ?thesis
    by (smt (verit, ccfv_SIG) Collect_cong Sup_set_def UNION_singleton_eq_range mem_Collect_eq)
qed

lemma atoms_simp:  (atoms ` (AF_proj_to_formula_set S)) = to_V `  (fset ` (A_of ` (proj S)))
proof -
  have  (atoms ` (AF_proj_to_formula_set S)) = {to_V ` fset A | A. A  A_of ` (proj S)}
    unfolding AF_proj_to_formula_set_def using atoms_to_V_un by auto
  also have ... = to_V `  (fset ` (A_of ` (proj S)))
    by blast
  finally show ?thesis .
qed

lemma val_from_interp: 𝒜. J. 𝒜 = to_valuation J
proof
  fix 𝒜
  define J_bare where J_bare = {Pos a |(a::'v). 𝒜 a}  {Neg a |a. ¬ 𝒜 a}
  then have interp_J_bare: is_interpretation J_bare
    unfolding is_interpretation_def
    by force
  then have total_J_bare: total (interp_of J_bare)
    unfolding total_def using J_bare_def
    by (metis (mono_tags, lifting) Abs_propositional_interpretation_inverse Un_iff belong_to.rep_eq
        mem_Collect_eq to_V.simps)
  define J where J = total_interp_of J_bare
  have 𝒜 = to_valuation J
  proof
    fix a::'v
    show 𝒜 a = to_valuation J a
      using J_def J_bare_def Abs_propositional_interpretation_inverse 
        Abs_total_interpretation_inverse interp_J_bare total_J_bare to_valuation_def val_strip_pos
      by fastforce
  qed
  then show J. 𝒜 = to_valuation J
    by fast
qed

lemma interp_from_val: J. 𝒜. 𝒜 = to_valuation J
  unfolding to_valuation_def by auto


lemma compactness_unsat: (¬ sat (S::'v formula set))  (sS. finite s  ¬ sat s)
  using compactness[of S] unfolding fin_sat_def by blast

lemma never_enabled_finite_subset: 
  J. ¬ enabled_set 𝒩 J  𝒩'𝒩. finite 𝒩'  (J. ¬ enabled_set 𝒩' J)
proof -
  assume not_enab_N: J. ¬ enabled_set 𝒩 J
  then have ¬ sat (AF_assertions_to_formula_set 𝒩)
    unfolding sat_def using equiv_enabled_assertions_sema[of 𝒩] val_from_interp
    by metis
  then obtain S' where S'_sub: S'  AF_assertions_to_formula ` 𝒩 and S'_fin: finite S' and
    S'_unsat: ¬ sat S'
    using compactness_unsat unfolding AF_assertions_to_formula_set_def by metis
  obtain 𝒩' where N'_sub: 𝒩'  𝒩 and N'_fin: finite 𝒩'
    and S'_im: S' = AF_assertions_to_formula ` 𝒩'
    using finite_subset_image[OF S'_fin S'_sub] by blast
  have not_enab_N': J. ¬ enabled_set 𝒩' J
    using equiv_enabled_assertions_sema[of 𝒩'] S'_unsat S'_im interp_from_val 
    unfolding sat_def AF_assertions_to_formula_set_def by blast
  then show 𝒩'  𝒩. finite 𝒩'  (J. ¬ enabled_set 𝒩' J)
    using N'_sub N'_fin by auto
qed


lemma compactness_AF_proj: (J. ¬ J p2 𝒩)  (𝒩'𝒩. finite 𝒩'  (J. ¬ J p2 𝒩'))
proof -
  define  where  = AF_proj_to_formula_set 𝒩
  have (J. ¬ J p2 𝒩)  (J. F. ¬ formula_semantics (to_valuation J) F)
    by (simp add: ℱ_def equiv_prop_entail2_sema2)
  also have 
    (J. F. ¬ formula_semantics (to_valuation J) F)  (𝒜. F. ¬ formula_semantics 𝒜 F)
    using val_from_interp by metis
  also have (𝒜. F. ¬ formula_semantics 𝒜 F)  (¬ sat )
    unfolding sat_def by blast
  also have (¬ sat )  (ℱ'. finite ℱ'  ¬ sat ℱ')
    using compactness_unsat[of ] .
  also have (ℱ'. finite ℱ'  ¬ sat ℱ')  (ℱ'. finite ℱ'  (𝒜. Fℱ'. ¬ formula_semantics 𝒜 F))
    unfolding sat_def by auto
  also have ...  (ℱ'. finite ℱ'  (J. Fℱ'. ¬ formula_semantics (to_valuation J) F))
    by (metis val_from_interp)
  also have ...  (𝒩'𝒩. finite 𝒩'  (J. ¬ J p2 𝒩'))
  proof
    assume ℱ'. finite ℱ'  (J. Fℱ'. ¬ formula_semantics (to_valuation J) F)
    then obtain ℱ' where F'_sub: ℱ' and F'_fin: finite ℱ' and
      F'_unsat: J. Fℱ'. ¬ formula_semantics (to_valuation J) F
      by auto
    have Fℱ'. 𝒞(proj 𝒩). AF_to_formula 𝒞 = F
      using F'_sub ℱ_def unfolding AF_proj_to_formula_set_def by blast
    then obtain 𝒩' where F'_is_map: ℱ' = AF_to_formula ` 𝒩' and N'_in_proj: 𝒩'  proj 𝒩 and
      N'_fin: finite 𝒩'
      using F'_fin
      by (metis AF_proj_to_formula_set_def F'_sub ℱ_def finite_subset_image)
    have proj 𝒩' = 𝒩'                               
      using N'_in_proj unfolding propositional_projection_def by blast
    then have F'_is: ℱ' = AF_proj_to_formula_set 𝒩'
      unfolding AF_proj_to_formula_set_def using F'_is_map by simp
    have N'_sub: 𝒩'  𝒩
      using prop_proj_in N'_in_proj by auto
    have N'_unsat: J. ¬ J p2 𝒩'
      using equiv_prop_entail2_sema2[of _ 𝒩'] F'_is F'_unsat 
      by blast
    show 𝒩'𝒩. finite 𝒩'  (J. ¬ J p2 𝒩')
      using N'_sub N'_fin N'_unsat by blast
  next
    assume 𝒩'𝒩. finite 𝒩'  (J. ¬ J p2 𝒩')
    then obtain 𝒩' where N'_sub: 𝒩'  𝒩 and N'_fin: finite 𝒩' and N'_unsat: J. ¬ J p2 𝒩'
      by auto
    define ℱ' where ℱ' = AF_proj_to_formula_set 𝒩'
    then have ℱ'  
      using N'_sub unfolding ℱ_def AF_proj_to_formula_set_def propositional_projection_def by blast
    moreover have finite ℱ'
      using ℱ'_def N'_fin unfolding AF_proj_to_formula_set_def propositional_projection_def by simp
    moreover have J. Fℱ'. ¬ formula_semantics (to_valuation J) F
      using N'_unsat equiv_prop_entail2_sema2[of _ 𝒩'] unfolding ℱ'_def by blast
    ultimately show ℱ'. finite ℱ'  (J. Fℱ'. ¬ formula_semantics (to_valuation J) F)
      by auto
  qed
  finally show (J. ¬ J p2 𝒩)  (𝒩'𝒩. finite 𝒩'  (J. ¬ J p2 𝒩'))
    .
qed

lemma prop_unsat_compactness:
  propositionally_unsatisfiable A   B  A. finite B  propositionally_unsatisfiable B
  by (meson compactness_AF_proj equiv_prop_entails propositionally_unsatisfiable_def)

definition ℰ_from :: ('f, 'v) AF set  ('f, 'v) AF set where
  ℰ_from 𝒩  {Pair bot {|neg a|} |a. 𝒞𝒩. a  fset (A_of 𝒞)}

lemma prop_proj_ℰ_from: proj (ℰ_from 𝒩) = ℰ_from 𝒩
  unfolding propositional_projection_def ℰ_from_def by auto

lemma prop_proj_sub: proj 𝒩 = 𝒩  𝒩'  𝒩  proj 𝒩' = 𝒩'
  unfolding propositional_projection_def by blast

lemma prop_proj_distrib: proj (A  B) = proj A  proj B
  unfolding propositional_projection_def by blast

lemma v_in_ℰ: Pair bot {|Pos v|}  ℰ_from 𝒩  Pair bot {|Neg v|}  ℰ_from 𝒩 
  𝒞𝒩. v  to_V ` (fset (A_of 𝒞))
  unfolding ℰ_from_def by (smt (verit, ccfv_threshold) AF.sel(2) fthe_felem_eq image_iff
    mem_Collect_eq neg.simps(1) neg.simps(2) to_V.elims to_V.simps(1) to_V.simps(2))

lemma a_in_ℰ: J. J p2 ℰ_from 𝒩  Pair bot {|neg a|}  ℰ_from 𝒩 
  ¬ (Pair bot {|a|}  ℰ_from 𝒩)
proof
  assume
    e_sat: J. J p2 ℰ_from 𝒩  and
    neg_a_in: Pair bot {|neg a|}  ℰ_from 𝒩 and
    a_in: AF.Pair bot {|a|}  ℰ_from 𝒩
  obtain J where J_sat_e: J p2 ℰ_from 𝒩
    using e_sat by blast
  have neg_a_in_J: neg a  total_strip J
    using a_in J_sat_e unfolding propositional_model2_def ℰ_from_def enabled_projection_def
      propositional_projection_def enabled_def by (smt (verit, ccfv_SIG) AF.collapse AF.inject
      bot_fset.rep_eq empty_iff empty_subsetI finsert.rep_eq insert_subset mem_Collect_eq
      neg.simps(1) neg.simps(2) to_V.elims val_strip_neg val_strip_pos)
  have neg a  total_strip J  ¬ J p2 ℰ_from 𝒩
    using neg_a_in J_sat_e enabled_def
      enabled_projection_def prop_proj_ℰ_from propositional_model2_def by fastforce
  then show False
    using neg_a_in_J J_sat_e by blast
qed

lemma equiv_ℰ_enabled_𝒩:
  shows J p2 ℰ_from 𝒩  enabled_set 𝒩 J
  unfolding propositional_model2_def enabled_set_def enabled_def propositional_projection_def
    enabled_projection_def
proof
  assume empty_proj_E: {} = {F_of 𝒞 |𝒞. 𝒞  {𝒞  ℰ_from 𝒩. F_of 𝒞 = bot} 
    fset (A_of 𝒞)  total_strip J}
  have 𝒞ℰ_from 𝒩. F_of 𝒞 = bot using ℰ_from_def[of 𝒩] by auto
  then have a_in_E: 𝒞ℰ_from 𝒩. afset (A_of 𝒞). a  total_strip J
    using empty_proj_E by blast
  then have 𝒞ℰ_from 𝒩. afset (A_of 𝒞). a  total_strip J
    unfolding ℰ_from_def by fastforce
  moreover have 𝒞𝒩. afset (A_of 𝒞). 𝒞'ℰ_from 𝒩. neg a  fset (A_of 𝒞')
    unfolding ℰ_from_def by fastforce
  ultimately have 𝒞𝒩. afset (A_of 𝒞). a  total_strip J
    by fastforce
  then show 𝒞𝒩. fset (A_of 𝒞)  total_strip J
    by blast
next
  assume enabled_𝒞: 𝒞𝒩. fset (A_of 𝒞)  total_strip J
  have 𝒞ℰ_from 𝒩. afset (A_of 𝒞). 𝒞'𝒩. neg a  fset (A_of 𝒞')
    unfolding ℰ_from_def
    by (smt (verit) AF.exhaust_sel AF.inject bot_fset.rep_eq empty_iff finsert.rep_eq insertE
        is_Pos.cases mem_Collect_eq neg.simps)
  then have 𝒞ℰ_from 𝒩. afset (A_of 𝒞). a  total_strip J
    using enabled_𝒞 by (meson belong_to.rep_eq neg_prop_interp subsetD)
  then have 𝒞ℰ_from 𝒩. (¬ fset (A_of 𝒞)  total_strip J)
    using ℰ_from_def by fastforce
  then show {} = {F_of 𝒞 |𝒞. 𝒞  {𝒞  ℰ_from 𝒩. F_of 𝒞 = bot}  fset (A_of 𝒞)  total_strip J}
    by blast
qed

definition AF_entails :: "('f, 'v) AF set  ('f, 'v) AF set  bool" (infix "AF" 50) where
  AF_entails  𝒩  (J. (enabled_set 𝒩 J   projJ J  F_of ` 𝒩))

lemma prop_unsat_to_AF_entails_bot: propositionally_unsatisfiable    AF {to_AF bot}
proof -
  assume prop_unsat_ℳ: propositionally_unsatisfiable 
  then show  AF {to_AF bot}
    unfolding AF_entails_def
  proof (intro allI impI)
    fix J
    assume enabled_set {to_AF bot} J
    have bot  (proj ) projJ J
      using prop_unsat_ℳ
      unfolding propositionally_unsatisfiable_def propositional_model_def
      by blast
    then have bot   projJ J
      using enabled_projection_def prop_proj_in
      by fastforce
    then have  projJ J  {bot}
      using bot_entails_empty entails_subsets
      by (meson empty_subsetI insert_subset)
    then show  projJ J  F_of ` {to_AF bot}
      by (auto simp add: F_of_to_AF)
  qed
qed

lemma enabled_set {} J
  unfolding enabled_set_def by blast

lemma (J. ¬ (enabled_set 𝒩 J))  ( AF 𝒩)
  unfolding AF_entails_def by blast
  
definition AF_entails_sound :: "('f, 'v) AF set  ('f, 'v) AF set  bool" (infix "⊨sAF" 50) where
  AF_entails_sound  𝒩  (J. (enabled_set 𝒩 J 
  sound_cons.entails_neg ((fml_ext ` (total_strip J))  (Pos ` ( projJ J))) (Pos ` F_of ` 𝒩)))

lemma distrib_proj:   𝒩 projJ J = ( projJ J)  (𝒩 projJ J)
  unfolding enabled_projection_def by auto

lemma distrib_proj_singleton:   {𝒞} projJ J = ( projJ J)  ({𝒞} projJ J)
  unfolding enabled_projection_def by auto

lemma enabled_union2: enabled_set (  𝒩) J  enabled_set 𝒩 J
  unfolding enabled_set_def by blast

lemma enabled_union1: enabled_set (  𝒩) J  enabled_set  J
  unfolding enabled_set_def by blast

lemma finite_subset_image_strong:
  assumes "finite U" and
    "(C  U. (D  W. P D = C  Q D))"
  shows "W'W. finite W'  U = P ` W'  (D' W'. Q D')"
  using assms
proof (induction U rule: finite_induct)
  case empty
  then show ?case by blast
next
  case (insert D' U)
  then obtain C' W'' where wpp_and_cp_assms: "W''  W" "finite W''" "U = P ` W''" "a  W''. Q a"
    "C'  W" "P C' = D'" "Q C'"
    by auto
  define W' where "W' = insert C' W''"
  then have (insert C' W') W  finite (insert C' W')  insert D' U = P ` (insert C' W') 
             (a(insert C' W'). Q a)
    using wpp_and_cp_assms by blast
  then show ?case
    by blast
qed

lemma all_to_ex: x. P x  x. P x for P by blast

lemma three_skolems:
  assumes U. P U   X Y Z. Q U X Y Z
  shows (X_of Y_of Z_of. (U. P U  Q U (X_of U) (Y_of U) (Z_of U))  thesis)  thesis
  using assms
  by metis

lemma finite_subset_with_prop:
  assumes Js. A = f ` Js  (JJs. P J) and
    finite C and
    B = C  A
  shows Js. B = f ` Js  (JJs. P J)  finite Js
proof -
  have B_fin: finite B using assms(2) assms(3) by simp
  have B_sub: B  A using assms(2) assms(3) by auto
  obtain Js where A_is: A = f ` Js and P_Js: JJs. P J
    using assms(1) by blast
  then have bB. JJs. b = f J  P J
    using B_sub by blast
  then obtain Js' where B = f ` Js' and finite Js' JJs'. P J
    using B_fin by (smt (verit, ccfv_threshold) B_sub assms(1) finite_subset_image subsetD)
  then show Js. B = f ` Js  (JJs. P J)  finite Js
    by blast
qed

lemma to_V_neg [simp]: to_V (neg a) = to_V a
  by (metis is_Neg_to_V is_Pos_to_V neg.simps(1) neg.simps(2) to_V.simps(1) to_V.simps(2))

  (* Splitting report Lemma 4, 1/2 *)
sublocale AF_cons_rel: consequence_relation "to_AF bot" AF_entails
proof
  show {to_AF bot} AF {}
    unfolding to_AF_def AF_entails_def enabled_def enabled_projection_def
    using bot_entails_empty by simp
next
  fix 𝒞
  show {𝒞} AF {𝒞}
    unfolding to_AF_def AF_entails_def enabled_def enabled_projection_def enabled_set_def
    using entails_reflexive by simp
next
  fix  𝒩 𝒫 𝒬
  assume m_in_n:   𝒩 and
    p_in_q: 𝒫  𝒬 and
    m_entails_p:  AF 𝒫
  show 𝒩 AF 𝒬
    unfolding to_AF_def AF_entails_def enabled_def enabled_projection_def enabled_set_def
  proof (rule allI, rule impI)
    fix J
    assume q_enabled: 𝒞𝒬. fset (A_of 𝒞)  total_strip J
    have {F_of 𝒞 |𝒞. 𝒞    fset (A_of 𝒞)  total_strip J}  
      {F_of 𝒞 |𝒞. 𝒞  𝒩  fset (A_of 𝒞)  total_strip J}
      using m_in_n by blast
    moreover have F_of ` 𝒫  F_of ` 𝒬
      using p_in_q by blast
    ultimately show {F_of 𝒞 |𝒞. 𝒞  𝒩  fset (A_of 𝒞)  total_strip J}  F_of ` 𝒬
      using m_entails_p  entails_subsets
      unfolding to_AF_def AF_entails_def enabled_def enabled_projection_def enabled_set_def
      by (metis (mono_tags, lifting) q_enabled p_in_q subset_iff)
  qed
next
  fix  𝒩 𝒞 ℳ' 𝒩'
  assume
    entails_c:  AF 𝒩  {𝒞} and
    c_entails: ℳ'  {𝒞} AF 𝒩'
  show   ℳ' AF 𝒩  𝒩'
    unfolding AF_entails_def
  proof (intro allI impI)
    fix J
    assume enabled_n: enabled_set (𝒩  𝒩') J
    {
      assume enabled_c: enabled_set {𝒞} J
      then have proj_enabled_c: {𝒞} projJ J = {F_of 𝒞} 
        unfolding enabled_projection_def using enabled_set_def by blast 
      have cut_hyp1:  projJ J  F_of ` 𝒩  {F_of 𝒞}
        using entails_c enabled_n enabled_c unfolding AF_entails_def by (simp add: enabled_set_def)
      have (ℳ'  {𝒞}) projJ J  F_of ` 𝒩'
        using c_entails enabled_union2[of 𝒩 𝒩' J, OF enabled_n] unfolding AF_entails_def by simp
      then have cut_hyp2: (ℳ' projJ J)  {F_of 𝒞}  F_of ` 𝒩'
        using proj_enabled_c distrib_proj_singleton by metis
      have   ℳ' projJ J  F_of ` (𝒩  𝒩')
        using entails_cut[OF cut_hyp1 cut_hyp2] distrib_proj by (simp add: image_Un) 
    }
    moreover
    {
      assume not_enabled_c: ¬ enabled_set {𝒞} J
      then have ℳ'  {𝒞} projJ J = ℳ' projJ J
        unfolding enabled_projection_def enabled_set_def by auto
      then have ℳ' projJ J  F_of ` 𝒩'
        using c_entails enabled_n unfolding AF_entails_def by (metis enabled_union2) 
      then have   ℳ' projJ J  F_of ` (𝒩  𝒩')
        using entails_subsets by (metis distrib_proj image_Un sup.cobounded2) 
    }
    ultimately show   ℳ' projJ J  F_of ` (𝒩  𝒩')
      by blast 
    qed
next
  fix  𝒩
  assume m_entails_n:  AF 𝒩
  consider (NotEnabled) J. ¬ enabled_set 𝒩 J | (Enabled) J. enabled_set 𝒩 J by blast
  then show M' N'. M'    N'  𝒩  finite M'  finite N'  M' AF N'
  proof cases
    case NotEnabled
    then obtain 𝒩' where N'_sub: 𝒩'  𝒩 and N'_fin: finite 𝒩' and
      sub_not_enab: J. ¬ enabled_set 𝒩' J
      using never_enabled_finite_subset[of 𝒩] by blast
    obtain ℳ' where ℳ'   and finite ℳ' and ℳ' AF 𝒩'
      using sub_not_enab unfolding AF_entails_def by blast
    then show ?thesis using N'_sub N'_fin by blast
  next
    case Enabled
    then obtain J' where J'_is: enabled_set 𝒩 J' by auto
    {
      fix J
      assume enabled_N: enabled_set 𝒩 J
      then have  projJ J  F_of ` 𝒩
        using m_entails_n unfolding AF_entails_def by simp 
      then obtain M' N' where mp_proj: M'   projJ J and
        np_proj: N'  F_of ` 𝒩 and mp_fin: finite M' and np_fin: finite N' and
        mp_entails_np: M'  N'
        using entails_compactness by metis
          
      have mp_with_f_of: C  M'. 𝒞  . F_of 𝒞 = C  enabled 𝒞 J 
        using mp_proj unfolding enabled_projection_def by blast
      have ℳ' . finite ℳ'  M' = F_of ` ℳ'  enabled_set ℳ' J
        using finite_subset_image_strong[OF mp_fin mp_with_f_of]
        unfolding enabled_set_def by blast
      then have m_fin_subset: ℳ'  . finite ℳ'  M' = ℳ' projJ J
        unfolding enabled_projection_def enabled_set_def by blast
          
      have np_with_f_of: C  N'. 𝒞  𝒩. F_of 𝒞 = C 
        using np_proj unfolding enabled_projection_def by blast
      have n_fin_subset: 𝒩' 𝒩. finite 𝒩'  N' = F_of ` 𝒩'
        using finite_subset_image[OF np_fin np_proj] .
          
      obtain ℳ' 𝒩' where m_n_subs: ℳ'   𝒩'  𝒩 finite ℳ' finite 𝒩' M' = ℳ' projJ J
        N' = F_of ` 𝒩'
        using m_fin_subset n_fin_subset by blast 
      then have m_proj: ℳ' projJ J  F_of ` 𝒩'
        using mp_entails_np by simp
          
      have enabled_N': enabled_set 𝒩' J
        using enabled_N m_n_subs(2) unfolding enabled_set_def by blast

      let ?ℳ'_selJ = {𝒞. 𝒞  ℳ'  enabled 𝒞 J}
      have ?ℳ'_selJ  ℳ' by simp
      have finite ({fset (A_of 𝒞) |𝒞. 𝒞  𝒩'  ?ℳ'_selJ}) (*{a. ∃𝒞∈𝒩'. a ∈ (fset (A_of 𝒞)) }›*)
        using m_n_subs(3) m_n_subs(4) by auto
      then obtain A𝒥' where AJ_is: fset A𝒥' = {fset (A_of 𝒞) |𝒞. 𝒞  𝒩'  ?ℳ'_selJ}
        by (smt (verit, best) fset_cases mem_Collect_eq)
      define 𝒥' where 𝒥' = Pair bot A𝒥'
      have afset (A_of 𝒥'). a t J
      proof
        fix a
        assume a  fset (A_of 𝒥')
        then have 𝒞𝒩'  ?ℳ'_selJ. a  fset (A_of 𝒞)
          unfolding 𝒥'_def using AJ_is by auto
        then show a t J 
          using enabled_N' unfolding enabled_set_def enabled_def belong_to_total_def belong_to_def
          by auto 
      qed
      moreover have F_of 𝒥' = bot
        unfolding 𝒥'_def
        by simp
      moreover have 𝒞𝒩'. fset (A_of 𝒞)  fset (A_of 𝒥')
        using AJ_is 𝒥'_def by auto
          
      ultimately have 
        ℳ' 𝒩' 𝒥'. ℳ'    𝒩'  𝒩  finite ℳ'  finite 𝒩'  ℳ' projJ J  F_of ` 𝒩' 
        enabled_set 𝒩' J  F_of 𝒥' = bot  (afset (A_of 𝒥'). a t J) 
        (fset (A_of 𝒥') = {fset (A_of 𝒞) |𝒞. 𝒞  𝒩'  {𝒞. 𝒞  ℳ'  enabled 𝒞 J}})
        using enabled_N' m_n_subs m_proj AJ_is 𝒥'_def
        by (metis (mono_tags, lifting) AF.sel(2))
    }
        
    (* In the pen-and-paper proof, the 𝒥'_of function is left vague, but in Isabelle the last
          conjunct that fully defines it is extremelly important. Non trivial is the addition of
          constraints from the enabled formulas in ℳ'_of J, but it is necessary to ensure that
          ‹(ℳ'_of J') projJ J' ⊆ (ℳ'_of J') projJ J› close to the end of the proof*)
    then obtain ℳ'_of 𝒩'_of 𝒥'_of where 
      fsets_from_J: enabled_set 𝒩 J  ℳ'_of J    𝒩'_of J  𝒩  finite (ℳ'_of J)  
      finite (𝒩'_of J)  (ℳ'_of J) projJ J  F_of ` (𝒩'_of J)  enabled_set (𝒩'_of J) J 
      F_of (𝒥'_of J) = bot  (afset (A_of (𝒥'_of J)). a t J) 
      (fset (A_of (𝒥'_of J)) = {fset (A_of 𝒞) |𝒞. 𝒞  (𝒩'_of J) 
        {𝒞. 𝒞  (ℳ'_of J)  enabled 𝒞 J}}) for J 
      using three_skolems[of "λU. enabled_set 𝒩 U" 
        "λJ ℳ' 𝒩' 𝒥'. ℳ'    𝒩'  𝒩  finite ℳ'  finite 𝒩'  ℳ' projJ J  F_of ` 𝒩'  
        enabled_set 𝒩' J  F_of 𝒥' = bot  (afset (A_of 𝒥'). a t J) 
        (fset (A_of 𝒥') = {fset (A_of 𝒞) |𝒞. 𝒞  𝒩'  {𝒞. 𝒞  ℳ'  enabled 𝒞 J}})"]
      by force
        
    let ?𝒥'_set = {𝒥'_of J |J. enabled_set 𝒩 J}
    have ex_Js: Js. ?𝒥'_set = 𝒥'_of ` Js  (JJs. enabled_set 𝒩 J)
      by blast
    have proj_prop_J': proj ?𝒥'_set = ?𝒥'_set
      using fsets_from_J unfolding propositional_projection_def by blast
    let ?𝒩'_un = {𝒩'_of J |J. enabled_set 𝒩 J}
    let ?ℳ'_un = {{𝒞. 𝒞  ℳ'_of J  enabled 𝒞 J} |J. enabled_set 𝒩 J}
    have A_of_enabled: enabled_set 𝒩 J  (fset (A_of (𝒥'_of J)) =
      {fset (A_of 𝒞) |𝒞. 𝒞  (𝒩'_of J)  {𝒞. 𝒞  (ℳ'_of J)  enabled 𝒞 J}}) for J
      using fsets_from_J by presburger
    have A_of_eq:  (fset ` A_of ` ?𝒥'_set) = 
       (fset ` A_of ` ?𝒩'_un)   (fset ` A_of ` ?ℳ'_un)
    proof -
      have  (fset ` A_of ` ?𝒥'_set) = {fset (A_of (𝒥'_of J)) |J. enabled_set 𝒩 J}
        by blast
      also have ... = {{fset (A_of 𝒞) |𝒞. 𝒞 
        (𝒩'_of J)  {𝒞. 𝒞  (ℳ'_of J)  enabled 𝒞 J}} |J. enabled_set 𝒩 J}
        using A_of_enabled by (metis (no_types, lifting))
      also have ... = (fset ` A_of ` (?𝒩'_un  ?ℳ'_un)) by blast
      finally show (fset ` A_of ` ?𝒥'_set) =
        (fset ` A_of ` ?𝒩'_un)   (fset ` A_of ` ?ℳ'_un)
        by simp
    qed
      
    have J. ¬ (enabled_set 𝒩 J)  ¬ (J p2 (ℰ_from 𝒩))
      using equiv_ℰ_enabled_𝒩 by blast
    then have not_enab_case: J. ¬ (enabled_set 𝒩 J)  ¬ (J p2 ?𝒥'_set  (ℰ_from 𝒩))
      using supset_not_model_p2 Un_upper2 by blast
    have J. enabled_set 𝒩 J  ¬ (J p2 ?𝒥'_set)
    proof (rule allI, rule impI, rule notI)
      fix J
      assume
        enab_N_loc: enabled_set 𝒩 J and
        entails_J: (J p2 ?𝒥'_set)
      have A_ok: fset (A_of (𝒥'_of J))  total_strip J
        using enab_N_loc fsets_from_J by force
      then have proj {𝒥'_of J} projJ J = {bot}
        using enab_N_loc fsets_from_J unfolding propositional_projection_def enabled_projection_def
        by (simp add: enabled_def)
      then have ¬ J p2 ?𝒥'_set
        using A_ok enab_N_loc unfolding propositional_model2_def enabled_def enabled_projection_def
          proj_prop_J' by auto
      then show False 
        using entails_J by auto
    qed
    then have enab_case: J. (enabled_set 𝒩 J)  ¬ (J p2 ?𝒥'_set  (ℰ_from 𝒩))
      using supset_not_model_p2 Un_upper2 by blast
    have J. ¬ (J p2 (?𝒥'_set  (ℰ_from 𝒩)))
      using not_enab_case enab_case by blast

    then obtain 𝒮 where S_sub: 𝒮  ?𝒥'_set  (ℰ_from 𝒩) and S_fin: finite 𝒮 and
      S_unsat: J. ¬ J p2 𝒮
      using compactness_AF_proj by meson
    have E_sat: sat (AF_proj_to_formula_set (ℰ_from 𝒩))
      unfolding sat_def using J'_is equiv_ℰ_enabled_𝒩 equiv_prop_entail2_sema2 by blast
    define 𝒮𝒥 where 𝒮𝒥 = 𝒮  ?𝒥'_set
    define 𝒮 where 𝒮 = 𝒮  (ℰ_from 𝒩)
    define 𝒮' where 𝒮' = {𝒞. 𝒞  𝒮  (to_V ` (fset (A_of 𝒞)))  (to_V `  (fset ` A_of ` 𝒮𝒥))}
    define 𝒮' where 𝒮' = 𝒮𝒥  𝒮'
    have proj_S':  proj  𝒮' = 𝒮'
      using proj_prop_J' prop_proj_ℰ_from S_sub prop_proj_sub prop_proj_distrib
      unfolding 𝒮'_def 𝒮𝒥_def 𝒮'_def 𝒮_def
      by (smt (verit) Int_iff mem_Collect_eq subsetI)
    have S_is: 𝒮 = (𝒮 - 𝒮')  𝒮'
      using S_sub 𝒮𝒥_def 𝒮_def 𝒮'_def 𝒮'_def by blast
    have a_from_E_to_J: neg a  (fset ` A_of ` 𝒮')  a  (fset ` A_of ` 𝒮𝒥) for a
    proof -
      fix a
      assume nega_in: neg a  (fset ` A_of ` 𝒮')
      then have to_V (neg a)  to_V ` (fset ` A_of ` 𝒮𝒥)
        unfolding 𝒮'_def by blast
      then have a_or_nega_in: a  (fset ` A_of ` 𝒮𝒥)  neg a  (fset ` A_of ` 𝒮𝒥)
        by (smt (verit) imageE neg.simps(1) neg.simps(2) to_V.elims) 
      obtain 𝒞1 where 𝒞1  ℰ_from 𝒩 and neg a  fset (A_of 𝒞1)
        using nega_in unfolding 𝒮'_def 𝒮_def ℰ_from_def by blast
      then obtain 𝒞 where 𝒞  𝒩 and a  fset (A_of 𝒞)
        unfolding ℰ_from_def by (smt (verit) AF.sel(2) bot_fset.rep_eq empty_iff finsert.rep_eq
          insert_iff mem_Collect_eq neg.simps(1) neg.simps(2) to_V.elims)
      then have in_N_in_J: J. (enabled_set 𝒩 J  a t J)
        using in_total_to_strip unfolding enabled_set_def enabled_def by blast 
      have b   (fset ` A_of ` 𝒮𝒥)  (J. enabled_set 𝒩 J  b t J) for b
      proof -
        have x  𝒮𝒥  b |∈| A_of x  J. enabled_set 𝒩 J  b  total_strip J for x
        proof -
          fix 𝒞2
          assume C2_in: 𝒞2  𝒮𝒥 and
            b_in: b  fset (A_of 𝒞2)
          obtain J where enab_J: enabled_set 𝒩 J and 𝒞2 = 𝒥'_of J
            using C2_in unfolding 𝒮𝒥_def by blast
          then have b  total_strip J
            using b_in fsets_from_J by auto
          then show J. enabled_set 𝒩 J  b  total_strip J
            using enab_J by blast
        qed
        then show b   (fset ` A_of ` 𝒮𝒥)  (J. enabled_set 𝒩 J  b t J)
          by clarsimp
      qed
      then have ¬  neg a  (fset ` A_of ` 𝒮𝒥)
        using in_N_in_J by fastforce 
      then show a  (fset ` A_of ` 𝒮𝒥)
        using a_or_nega_in by blast
    qed
    have empty_inter_in_S: to_V `  (fset ` A_of ` (𝒮 - 𝒮'))  to_V `  (fset ` A_of ` 𝒮') = {}
    proof (rule ccontr)
      assume contra: to_V `  (fset ` A_of ` (𝒮 - 𝒮'))  to_V `  (fset ` A_of ` 𝒮')  {}
      then obtain v where v_in1: v  to_V `  (fset ` A_of ` (𝒮 - 𝒮'))
        and v_in2: v  to_V `  (fset ` A_of ` 𝒮') by blast
      obtain 𝒞 where C_in: 𝒞  𝒮 - 𝒮' and v_in_C: v  to_V ` (fset (A_of 𝒞))
        using v_in1 by blast
      obtain a where C_is1: 𝒞 = Pair bot {|a|}
        using C_in unfolding 𝒮_def ℰ_from_def by blast
      then have v_is: v = to_V a
        using v_in_C by simp
      obtain 𝒞' where C'_in: 𝒞'  𝒮' and v_in_C': v  to_V ` (fset (A_of 𝒞'))
        using v_in2 by blast
      then obtain a' where v_is': v = to_V a' and a'_in: a'  fset (A_of 𝒞')
        by blast
      consider (J) 𝒞'  𝒮𝒥 | (E') 𝒞'  𝒮'
        using C'_in 𝒮'_def by blast
      then show False
      proof cases
        case J
        then have to_V ` (fset (A_of 𝒞'))  (to_V `  (fset ` A_of ` 𝒮𝒥))
          by blast
        then have to_V ` (fset (A_of 𝒞))  (to_V `  (fset ` A_of ` 𝒮𝒥))
          using C_is1 v_in_C' v_is by auto
        then have 𝒞  𝒮'
          unfolding 𝒮'_def using C_in by blast
        then show False
          using C_in by blast
      next
        case E'
        then consider (a) 𝒞' = Pair bot {|a|} | (nega) 𝒞' = Pair bot {|neg a|}
          unfolding 𝒮'_def 𝒮_def ℰ_from_def using v_in_C' v_is
            AF.sel(2) IntE empty_iff fset_simps(1) fset_simps(2) image_iff insert_iff
            mem_Collect_eq neg.simps(1) neg.simps(2) to_V.elims
          by (smt (verit, del_insts))
        then show False 
        proof cases
          case a
          then show ?thesis
            using E' a_in_ℰ Enabled equiv_ℰ_enabled_𝒩 C_in C_is1 unfolding 𝒮_def 𝒮'_def 
            by blast
        next
          case nega
          have 𝒞'  ℰ_from 𝒩 
            using E' unfolding 𝒮'_def 𝒮_def by auto
          moreover have 𝒞  ℰ_from 𝒩
            using C_in unfolding 𝒮_def by auto
          ultimately show ?thesis
            using a_in_ℰ nega C_is1 Enabled equiv_ℰ_enabled_𝒩 by blast
        qed
      qed
    qed
    then have empty_inter:  (atoms ` (AF_proj_to_formula_set (𝒮 - 𝒮'))) 
       (atoms ` (AF_proj_to_formula_set 𝒮')) = {}
      using atoms_simp proj_S' prop_proj_distrib prop_proj_sub
      by (smt (verit, ccfv_threshold) S_sub Un_subset_iff 𝒮 = 𝒮 - 𝒮'  𝒮' proj_prop_J'
        prop_proj_ℰ_from)
    have sat_rest: sat (AF_proj_to_formula_set (𝒮 - 𝒮'))
      using E_sat unfolding 𝒮'_def 𝒮_def AF_proj_to_formula_set_def
        propositional_projection_def sat_def by blast
    have S'_unsat: J. ¬ J p2 𝒮'
      using unsat_AF_simp[OF _ sat_rest empty_inter] S_unsat equiv_prop_entail2_sema2 S_is
        val_from_interp unfolding sat_def by metis
    have ex_fin_Js: Js. 𝒮𝒥 = 𝒥'_of ` Js  (JJs. enabled_set 𝒩 J)  finite Js
      using finite_subset_with_prop[OF ex_Js S_fin 𝒮𝒥_def] .
    then obtain Js where Js_fin: finite Js and Js_enab: JJs. enabled_set 𝒩 J and
      Js_is: 𝒥'_of ` Js = 𝒮𝒥
      by blast

    have fin_inter: finite ((fset ` A_of ` 𝒮𝒥)  (fset ` A_of ` 𝒩))
    proof
      have finite ((fset ` A_of ` 𝒮𝒥))
        unfolding 𝒮𝒥_def using S_fin image_Int_subset by simp
      then show (finite ((fset ` A_of ` 𝒮𝒥)))  (finite ( (fset ` A_of ` 𝒩)))
        by auto
    qed
    have a((fset ` A_of ` 𝒩)). 𝒞𝒩. a  fset (A_of 𝒞)
      by blast
    then obtain f where f_def: a((fset ` A_of ` 𝒩)). f a  𝒩  a  fset (A_of (f a))
      by metis
        (* the fact that 𝒩𝒥 is needed in the proof was found during the isabelle verification *)
    define 𝒩𝒥 where 𝒩𝒥 = (f ` ((fset ` A_of ` 𝒮𝒥)  (fset ` A_of ` 𝒩)))
    have nj_fin: finite 𝒩𝒥
      unfolding 𝒩𝒥_def using fin_inter by blast
    have nj_sub: 𝒩𝒥  𝒩
      unfolding 𝒩𝒥_def using f_def by blast
    have nj_as: (a((fset ` A_of ` 𝒮𝒥))((fset ` A_of ` 𝒩)).
      a  (fset ` A_of ` 𝒩𝒥))
      unfolding 𝒩𝒥_def using f_def by fast
        
    define ℳ' where ℳ' = {ℳ'_of J |J. J  Js}
    define 𝒩' where  𝒩' = {𝒩'_of J |J. J  Js}  𝒩𝒥
    then have ℳ'  
      unfolding ℳ'_def using fsets_from_J Js_enab by fast
    moreover have 𝒩'  𝒩
      unfolding 𝒩'_def using fsets_from_J Js_enab nj_sub by fast
    moreover have finite ℳ'
      unfolding ℳ'_def using fsets_from_J Js_fin Js_enab by auto
    moreover have finite 𝒩'
      unfolding 𝒩'_def using fsets_from_J Js_fin Js_enab nj_fin by auto
    moreover have ℳ' AF 𝒩' unfolding AF_entails_def
    proof (rule allI, rule impI)
      fix J
      assume enab_N': enabled_set 𝒩' J
      then have J p2 ℰ_from 𝒩'
        using equiv_ℰ_enabled_𝒩 by auto
      moreover have 𝒮'  ℰ_from 𝒩'
        proof
          fix 𝒞 
          assume C_in: 𝒞  𝒮'
          then obtain a where C_is: 𝒞 = Pair bot {|neg a|}
            unfolding 𝒮'_def 𝒮_def ℰ_from_def by blast
          then have neg a  (fset ` A_of ` 𝒮')
            using C_in using image_iff by fastforce
          then have a_in_SJ: a  (fset ` A_of ` 𝒮𝒥)
            using a_from_E_to_J by presburger
          have 𝒞'𝒩. a  fset (A_of 𝒞')
            using C_is C_in unfolding 𝒮'_def 𝒮_def by (smt (verit, ccfv_threshold)
              AF.sel(2) IntE J'_is ℰ_from_def a_in_ℰ bot_fset.rep_eq empty_iff equiv_ℰ_enabled_𝒩
              finsert.rep_eq insert_iff mem_Collect_eq to_V.elims to_V_neg)
          then have a  (fset ` A_of ` 𝒩)
            by blast 
          then have a  (fset ` A_of ` 𝒩')
            using nj_as a_in_SJ unfolding 𝒩'_def by simp 
          then show 𝒞  ℰ_from 𝒩'
            using C_is unfolding ℰ_from_def by blast
        qed
      ultimately have J p2 𝒮'
        unfolding 𝒮'_def 𝒮_def using subset_model_p2 by (metis (no_types, lifting))
      then have ¬ J p2 𝒮𝒥
        using subset_not_model S'_unsat unfolding 𝒮'_def by blast
      then have  J'Js. fset (A_of (𝒥'_of J'))  total_strip J
        unfolding propositional_model2_def 𝒮𝒥_def propositional_projection_def
          enabled_projection_def using Js_is
        by (smt (verit) Collect_cong Set.empty_def 𝒮𝒥_def enabled_def image_iff mem_Collect_eq)
      then obtain J' where J'_in: J'  Js and A_of_J'_in: fset (A_of (𝒥'_of J'))  total_strip J
        by blast
      then have enab_nj': enabled_set 𝒩 J'
        using Js_enab by blast
      then have (ℳ'_of J') projJ J'  F_of ` (𝒩'_of J')
        using fsets_from_J by auto
      moreover have (ℳ'_of J') projJ J'  (ℳ'_of J') projJ J
      proof -
        have 𝒞  ℳ'_of J'  enabled 𝒞 J'  enabled 𝒞 J for 𝒞
        proof -
          assume C_in: 𝒞  ℳ'_of J' and
            enabled 𝒞 J'
          then have fset (A_of 𝒞)  fset (A_of (𝒥'_of J'))
            using fsets_from_J[OF enab_nj'] by blast
          then show enabled 𝒞 J
            using A_of_J'_in unfolding enabled_def by auto
        qed
        then have (𝒞  ℳ'_of J'  enabled 𝒞 J')  (𝒞  ℳ'_of J'  enabled 𝒞 J) for 𝒞
          by (smt (verit, ccfv_threshold))
        then have {𝒞. 𝒞  ℳ'_of J'  enabled 𝒞 J'}  {𝒞. 𝒞  ℳ'_of J'  enabled 𝒞 J}
          by blast
        then show (ℳ'_of J') projJ J'  (ℳ'_of J') projJ J
          unfolding enabled_projection_def by blast
      qed
      ultimately have entails_one: (ℳ'_of J') projJ J  F_of ` (𝒩'_of J')
        using entails_subsets by blast
      have subs_M: ℳ'_of J' projJ J  ℳ' projJ J
        using J'_in using enabled_projection_def unfolding ℳ'_def by auto
      have subs_N: F_of ` (𝒩'_of J')  F_of ` 𝒩'
        using J'_in unfolding 𝒩'_def by blast
      show ℳ' projJ J  F_of ` 𝒩'
        using entails_subsets[OF subs_M subs_N entails_one] .
    qed

    ultimately show ℳ' 𝒩'. ℳ'    𝒩'  𝒩  finite ℳ'  finite 𝒩'  ℳ' AF 𝒩'
      by blast
  qed
qed

sublocale neg_ext_sound_cons_rel: consequence_relation "Pos bot" sound_cons.entails_neg
  using sound_cons.ext_cons_rel by simp

(* Splitting report Lemma 4, 2/2 *)
lemma AF_ext_sound_cons_rel: consequence_relation (to_AF bot) AF_entails_sound
proof (standard)
  show {to_AF bot} ⊨sAF {}
   unfolding AF_entails_sound_def enabled_def enabled_projection_def
  proof (rule allI, rule impI)
   fix J
   assume enabled_set {} J
   have bot_in: {Pos bot}  Pos ` {C. C = F_of (to_AF bot)  fset (A_of (to_AF bot))  total_strip J}
     unfolding to_AF_def by simp
   have sound_cons.entails_neg (fml_ext ` total_strip J 
     Pos ` {C. C = F_of (to_AF bot)  fset (A_of (to_AF bot))  total_strip J}) {}
     using sound_cons.bot_entails_empty sound_cons.entails_subsets bot_in
     by (smt (verit, ccfv_threshold) AF.sel(2) Un_iff bot_fset.rep_eq
       consequence_relation.bot_entails_empty consequence_relation.entails_subsets empty_subsetI
       image_iff mem_Collect_eq sound_cons.ext_cons_rel subset_eq to_AF_def)
   then show fml_ext ` total_strip J  
     Pos ` {F_of 𝒞 |𝒞. 𝒞  {to_AF bot}  fset (A_of 𝒞)  total_strip J} ⊨s Pos ` F_of ` {}
     by clarsimp
 qed
next
  fix 𝒞 :: "('f, 'v) AF"
  have Pos ` {F_of Ca |Ca. Ca  {𝒞}  fset (A_of Ca)  total_strip J}  (Pos ` F_of ` {𝒞})
    by auto
  show {𝒞} ⊨sAF {𝒞}
    unfolding AF_entails_sound_def enabled_def enabled_projection_def enabled_set_def
  proof (rule allI, rule impI)
    fix J
    assume a_of_C_in: 𝒞{𝒞}. fset (A_of 𝒞)  total_strip J
    have sound_cons.entails_neg (Pos (F_of 𝒞)  fml_ext ` total_strip J) {Pos (F_of 𝒞)}
      using sound_cons.entails_reflexive[of "F_of 𝒞"]
      by (smt (verit, best) Set.insert_mono bot.extremum consequence_relation.entails_reflexive
        consequence_relation.entails_subsets sound_cons.ext_cons_rel)
    then show fml_ext ` total_strip J  
      Pos ` {F_of 𝒞' |𝒞'. 𝒞'  {𝒞}  fset (A_of 𝒞')  total_strip J} ⊨s Pos ` F_of ` {𝒞}
      using a_of_C_in by clarsimp
  qed
next
  fix  𝒩 𝒫 𝒬
  assume m_in_n:   𝒩 and
    p_in_q: 𝒫  𝒬 and
    m_entails_p:  ⊨sAF 𝒫
  show 𝒩 ⊨sAF 𝒬
    unfolding AF_entails_sound_def enabled_def enabled_projection_def enabled_set_def
  proof (rule allI, rule impI)
    fix J
    assume q_enabled: 𝒞𝒬. fset (A_of 𝒞)  total_strip J
    have {F_of 𝒞 |𝒞. 𝒞    fset (A_of 𝒞)  total_strip J} 
      {F_of 𝒞 |𝒞. 𝒞  𝒩  fset (A_of 𝒞)  total_strip J}
      using m_in_n by blast
    moreover have F_of ` 𝒫  F_of ` 𝒬
      using p_in_q by blast
    ultimately show sound_cons.entails_neg (fml_ext ` total_strip J 
      Pos ` {F_of 𝒞 |𝒞. 𝒞  𝒩  fset (A_of 𝒞)  total_strip J}) (Pos ` F_of ` 𝒬)
      using m_entails_p sound_cons.entails_subsets m_in_n p_in_q q_enabled
      unfolding AF_entails_sound_def enabled_def enabled_projection_def enabled_set_def
      by (smt (z3) Un_iff consequence_relation.entails_subsets image_iff mem_Collect_eq
        sound_cons.ext_cons_rel subset_eq)
  qed
next
  fix  𝒩 𝒞 ℳ' 𝒩'
  assume
    entails_c:  ⊨sAF 𝒩  {𝒞} and
    c_entails: ℳ'  {𝒞} ⊨sAF 𝒩'
  show   ℳ' ⊨sAF 𝒩  𝒩'
    unfolding AF_entails_sound_def
  proof (intro allI impI)
    fix J
    assume enabled_n: enabled_set (𝒩  𝒩') J
    {
      assume enabled_c: enabled_set {𝒞} J
      then have proj_enabled_c: {𝒞} projJ J = {F_of 𝒞}
        unfolding enabled_projection_def using enabled_set_def by blast
      have sound_cons.entails_neg (fml_ext ` total_strip J  Pos ` ( projJ J))
        (Pos ` F_of ` (𝒩  {𝒞}))
        using entails_c enabled_n enabled_c unfolding AF_entails_sound_def
        by (metis Un_iff enabled_set_def)
      then have cut_hyp1: sound_cons.entails_neg (fml_ext ` total_strip J  Pos ` ( projJ J))
        (Pos ` F_of ` 𝒩  {Pos (F_of 𝒞)})
        by force
      have sound_cons.entails_neg (fml_ext ` total_strip J  Pos ` (ℳ'  {𝒞} projJ J))
        (Pos ` F_of ` 𝒩')
        using c_entails enabled_n enabled_union2 unfolding AF_entails_sound_def by blast
      then have cut_hyp2: sound_cons.entails_neg
        (fml_ext ` total_strip J  Pos ` (ℳ' projJ J)  {Pos (F_of 𝒞)}) (Pos ` F_of ` 𝒩')
       by (metis Un_empty_right Un_insert_right distrib_proj image_insert proj_enabled_c)
       have sound_cons.entails_neg (fml_ext ` total_strip J  Pos ` (  ℳ' projJ J))
         (Pos ` F_of ` (𝒩  𝒩'))
         using neg_ext_sound_cons_rel.entails_cut[OF cut_hyp1 cut_hyp2]  distrib_proj[of  ℳ' J]
           image_Un by (smt (verit, del_insts) Un_commute Un_left_absorb Un_left_commute)
    }
    moreover
    {
      assume not_enabled_c: ¬ enabled_set {𝒞} J
      then have ℳ'  {𝒞} projJ J = ℳ' projJ J
        unfolding enabled_projection_def enabled_set_def by auto
      then have sound_cons.entails_neg (fml_ext ` total_strip J  Pos ` (ℳ' projJ J))
        (Pos ` F_of ` 𝒩')
        using c_entails enabled_n enabled_union2 unfolding AF_entails_sound_def by metis
      then have sound_cons.entails_neg (fml_ext ` total_strip J  Pos ` (  ℳ' projJ J))
        (Pos ` F_of ` (𝒩  𝒩'))
        using neg_ext_sound_cons_rel.entails_subsets
        by (smt (verit, del_insts) Un_iff distrib_proj image_Un subsetI)
    }
    ultimately
    show sound_cons.entails_neg (fml_ext ` total_strip J  Pos ` (  ℳ' projJ J))
      (Pos ` F_of ` (𝒩  𝒩'))
      by blast
  qed
next
  fix  𝒩
  assume m_entails_n:  ⊨sAF 𝒩
  consider (NotEnabled) J. ¬ enabled_set 𝒩 J | (Enabled) J. enabled_set 𝒩 J by blast
  then show M' N'. M'    N'  𝒩  finite M'  finite N'  M' ⊨sAF N'
  proof cases
    case NotEnabled
    then obtain 𝒩' where N'_sub: 𝒩'  𝒩 and N'_fin: finite 𝒩' and
      sub_not_enab: J. ¬ enabled_set 𝒩' J
      using never_enabled_finite_subset[of 𝒩] by blast
    obtain ℳ' where ℳ'   and finite ℳ' and ℳ' ⊨sAF 𝒩'
      using sub_not_enab unfolding AF_entails_sound_def by blast
    then show ?thesis using N'_sub N'_fin by blast
  next
    case Enabled
    then obtain J' where J'_is: enabled_set 𝒩 J' by auto
    {
      fix J
      assume enabled_N: enabled_set 𝒩 J
      then have sound_cons.entails_neg (fml_ext ` total_strip J  Pos ` ( projJ J)) (Pos ` F_of ` 𝒩)
        using m_entails_n unfolding AF_entails_sound_def by blast
      then obtain MJ' N' where mj_in: MJ'  fml_ext ` total_strip J  Pos ` ( projJ J) and
        np_proj: N'  Pos ` F_of ` 𝒩 and mjp_fin: finite MJ' and np_fin: finite N' and
        mjp_entails_np: sound_cons.entails_neg  MJ' N'
        using neg_ext_sound_cons_rel.entails_compactness by metis

      define M' where "M' = MJ'  Pos ` ( projJ J)"
      then have mp_fin: finite M'
        using mjp_fin by auto
      have mp_with_f_of: C  M'. 𝒞  . Pos (F_of 𝒞) = C  enabled 𝒞 J
        using mj_in unfolding enabled_projection_def M'_def by blast
      have ℳ' . finite ℳ'  M' = Pos ` F_of ` ℳ'  enabled_set ℳ' J
        using finite_subset_image_strong[of M'  "(λx. Pos (F_of x))" "λx. enabled x J", OF mp_fin mp_with_f_of]
        unfolding enabled_set_def by blast
      then have ex_mp: ℳ'. finite ℳ'  Pos ` (ℳ' projJ J) = M'
        unfolding enabled_projection_def enabled_set_def by blast
      then obtain ℳ' where mp_props: ℳ'   finite ℳ' Pos ` (ℳ' projJ J) = M' by auto

      let ?ℳ'_selJ = {𝒞. 𝒞  ℳ'  enabled 𝒞 J}
      have ?ℳ'_selJ  ℳ' by simp
      have finite ({fset (A_of 𝒞) |𝒞. 𝒞  ?ℳ'_selJ}) (*{a. ∃𝒞∈𝒩'. a ∈ (fset (A_of 𝒞)) }›*)
        using mp_props by auto
      then obtain 𝒜' where AM_is: fset 𝒜' = ({fset (A_of 𝒞) |𝒞. 𝒞  ?ℳ'_selJ})
        using fin_set_fset by fastforce
      then have AM_in_J: fset 𝒜'  total_strip J
        unfolding enabled_def by blast
      define J' where "J' = (MJ'  fml_ext ` total_strip J)"
      then have jp_fin: finite J'
        using mjp_fin by blast
      then obtain 𝒥' where jp_props: "𝒥'  total_strip J" "fml_ext ` 𝒥' = J'" "finite 𝒥'"
        using J'_def by (metis Int_lower2 finite_subset_image)
      then obtain 𝒜𝒥' where AJ_is: fset 𝒜𝒥' = 𝒥'
        using fin_set_fset by blast
      then have AJ_in_J: fset 𝒜𝒥'  total_strip J
        using jp_props by auto
      define 𝒥f' where 𝒥f' = Pair bot (𝒜𝒥' |∪| 𝒜')
      then have Jf_in: fset (A_of 𝒥f')  total_strip J using AM_in_J AJ_in_J by simp
      have Jf_bot: F_of 𝒥f' = bot using 𝒥f'_def by auto
      have AM_in_Jf: 𝒞ℳ'. enabled 𝒞 J  fset (A_of 𝒞)  fset (A_of 𝒥f')
        using 𝒥f'_def AM_is by auto

      have np_with_f_of: C  N'. 𝒞  𝒩. Pos (F_of 𝒞) = C
        using np_proj unfolding enabled_projection_def by blast
      have n_fin_subset: 𝒩' 𝒩. finite 𝒩'  N' = Pos ` F_of ` 𝒩'
        using finite_subset_image[OF np_fin, of "λx. Pos (F_of x)" 𝒩] np_proj by auto
      then obtain 𝒩' where np_props: 𝒩'  𝒩 finite 𝒩' N' = Pos ` F_of ` 𝒩'
        by blast
      have enab_np: enabled_set 𝒩' J
        using enabled_N np_props unfolding enabled_set_def by blast

      have mjp_is: MJ' = Pos ` (ℳ' projJ J)  fml_ext ` 𝒥'
        using mj_in M'_def J'_def mp_props jp_props by auto
      have sound_cons.entails_neg ((Pos ` (ℳ' projJ J)) fml_ext ` 𝒥') (Pos ` F_of ` 𝒩')
        using np_props mjp_entails_np unfolding mjp_is by blast
      then have fin_entail: sound_cons.entails_neg ((Pos ` (ℳ' projJ J)) fml_ext ` (fset (A_of 𝒥f'))) (Pos ` F_of ` 𝒩')
        using neg_ext_sound_cons_rel.entails_subsets[of
          "(Pos ` (ℳ' projJ J)) fml_ext ` 𝒥'" "(Pos ` (ℳ' projJ J)) fml_ext ` (fset (A_of 𝒥f'))"
          "Pos ` F_of ` 𝒩'" "Pos ` F_of ` 𝒩'"] AJ_is unfolding 𝒥f'_def by (simp add: image_Un subsetI)

      have ℳ' 𝒩' 𝒥'. ℳ'    fset (A_of 𝒥')  total_strip J  𝒩'  𝒩 
        finite ℳ'   finite 𝒩'  F_of 𝒥' = bot  enabled_set 𝒩' J 
        (𝒞ℳ'. enabled 𝒞 J  fset (A_of 𝒞)  fset (A_of 𝒥')) 
        sound_cons.entails_neg ((Pos ` (ℳ' projJ J)) fml_ext ` (fset (A_of 𝒥'))) (Pos ` F_of ` 𝒩')
        using mp_props np_props fin_entail enab_np Jf_in Jf_bot 𝒥f'_def AJ_is AM_is AM_in_Jf AF.sel(2) by blast
    }

    then obtain ℳ'_of 𝒩'_of 𝒥'_of where
      fsets_from_J: enabled_set 𝒩 J  ℳ'_of J    fset (A_of (𝒥'_of J))  total_strip J  𝒩'_of J  𝒩 
      finite (ℳ'_of J)  finite (𝒩'_of J)  F_of (𝒥'_of J) = bot  enabled_set (𝒩'_of J) J 
      (𝒞(ℳ'_of J). enabled 𝒞 J  fset (A_of 𝒞)  fset (A_of (𝒥'_of J))) 
      sound_cons.entails_neg (Pos ` (ℳ'_of J projJ J)  fml_ext ` (fset (A_of (𝒥'_of J)))) (Pos ` F_of ` 𝒩'_of J) for J
      by metis

    let ?𝒥'_set = {𝒥'_of J |J. enabled_set 𝒩 J}
    have ex_Js: Js. ?𝒥'_set = 𝒥'_of ` Js  (JJs. enabled_set 𝒩 J)
      by blast
    have proj_prop_J': proj ?𝒥'_set = ?𝒥'_set
      using fsets_from_J unfolding propositional_projection_def by blast
    let ?𝒩'_un = {𝒩'_of J |J. enabled_set 𝒩 J}
    let ?ℳ'_un = {{𝒞. 𝒞  ℳ'_of J  enabled 𝒞 J} |J. enabled_set 𝒩 J}

    have J. ¬ (enabled_set 𝒩 J)  ¬ (J p2 (ℰ_from 𝒩))
      using equiv_ℰ_enabled_𝒩 by blast
    then have not_enab_case: J. ¬ (enabled_set 𝒩 J)  ¬ (J p2 ?𝒥'_set  (ℰ_from 𝒩))
      using supset_not_model_p2 Un_upper2 by blast
    have J. enabled_set 𝒩 J  ¬ (J p2 ?𝒥'_set)
    proof (rule allI, rule impI, rule notI)
      fix J
      assume
        enab_N_loc: enabled_set 𝒩 J and
        entails_J: (J p2 ?𝒥'_set)
      have A_ok: fset (A_of (𝒥'_of J))  total_strip J
        using enab_N_loc fsets_from_J by force
      then have proj {𝒥'_of J} projJ J = {bot}
        using enab_N_loc fsets_from_J unfolding propositional_projection_def enabled_projection_def
        by (simp add: enabled_def)
      then have ¬ J p2 ?𝒥'_set
        using A_ok enab_N_loc unfolding propositional_model2_def enabled_def enabled_projection_def
          proj_prop_J' by auto
      then show False
        using entails_J by auto
    qed
    then have enab_case: J. (enabled_set 𝒩 J)  ¬ (J p2 ?𝒥'_set  (ℰ_from 𝒩))
      using supset_not_model_p2 Un_upper2 by blast
    have J. ¬ (J p2 (?𝒥'_set  (ℰ_from 𝒩)))
      using not_enab_case enab_case by blast

    then obtain 𝒮 where S_sub: 𝒮  ?𝒥'_set  (ℰ_from 𝒩) and S_fin: finite 𝒮 and
      S_unsat: J. ¬ J p2 𝒮
      using compactness_AF_proj by meson
    have E_sat: sat (AF_proj_to_formula_set (ℰ_from 𝒩))
      unfolding sat_def using J'_is equiv_ℰ_enabled_𝒩 equiv_prop_entail2_sema2 by blast
    define 𝒮𝒥 where 𝒮𝒥 = 𝒮  ?𝒥'_set
    define 𝒮 where 𝒮 = 𝒮  (ℰ_from 𝒩)
    define 𝒮' where 𝒮' = {𝒞. 𝒞  𝒮  (to_V ` (fset (A_of 𝒞)))  (to_V `  (fset ` A_of ` 𝒮𝒥))}
    define 𝒮' where 𝒮' = 𝒮𝒥  𝒮'
    have proj_S':  proj  𝒮' = 𝒮'
      using proj_prop_J' prop_proj_ℰ_from S_sub prop_proj_sub prop_proj_distrib
      unfolding 𝒮'_def 𝒮𝒥_def 𝒮'_def 𝒮_def
      by (smt (verit) Int_iff mem_Collect_eq subsetI)
    have S_is: 𝒮 = (𝒮 - 𝒮')  𝒮'
      using S_sub 𝒮𝒥_def 𝒮_def 𝒮'_def 𝒮'_def by blast
    have a_from_E_to_J: neg a  (fset ` A_of ` 𝒮')  a  (fset ` A_of ` 𝒮𝒥) for a
    proof -
      fix a
      assume nega_in: neg a  (fset ` A_of ` 𝒮')
      then have to_V (neg a)  to_V ` (fset ` A_of ` 𝒮𝒥)
        unfolding 𝒮'_def by blast
      then have a_or_nega_in: a  (fset ` A_of ` 𝒮𝒥)  neg a  (fset ` A_of ` 𝒮𝒥)
        by (smt (verit) imageE neg.simps(1) neg.simps(2) to_V.elims)
      obtain 𝒞1 where 𝒞1  ℰ_from 𝒩 and neg a  fset (A_of 𝒞1)
        using nega_in unfolding 𝒮'_def 𝒮_def ℰ_from_def by blast
      then obtain 𝒞 where 𝒞  𝒩 and a  fset (A_of 𝒞)
        unfolding ℰ_from_def by (smt (verit) AF.sel(2) bot_fset.rep_eq empty_iff finsert.rep_eq
          insert_iff mem_Collect_eq neg.simps(1) neg.simps(2) to_V.elims)
      then have in_N_in_J: J. (enabled_set 𝒩 J  a t J)
        using in_total_to_strip unfolding enabled_set_def enabled_def by blast
      have b   (fset ` A_of ` 𝒮𝒥)  (J. enabled_set 𝒩 J  b t J) for b
      proof -
        have x  𝒮𝒥  b |∈| A_of x  J. enabled_set 𝒩 J  b  total_strip J for x
        proof -
          fix 𝒞2
          assume C2_in: 𝒞2  𝒮𝒥 and
            b_in: b  fset (A_of 𝒞2)
          obtain J where enab_J: enabled_set 𝒩 J and 𝒞2 = 𝒥'_of J
            using C2_in unfolding 𝒮𝒥_def by blast
          then have b  total_strip J
            using b_in fsets_from_J by (meson basic_trans_rules(31))
          then show J. enabled_set 𝒩 J  b  total_strip J
            using enab_J by blast
        qed
        then show b   (fset ` A_of ` 𝒮𝒥)  J. enabled_set 𝒩 J  b t J
          by clarsimp
      qed
      then have ¬  neg a  (fset ` A_of ` 𝒮𝒥)
        using in_N_in_J by fastforce
      then show a  (fset ` A_of ` 𝒮𝒥)
        using a_or_nega_in by blast
    qed
    have empty_inter_in_S: to_V `  (fset ` A_of ` (𝒮 - 𝒮'))  to_V `  (fset ` A_of ` 𝒮') = {}
    proof (rule ccontr)
      assume contra: to_V `  (fset ` A_of ` (𝒮 - 𝒮'))  to_V `  (fset ` A_of ` 𝒮')  {}
      then obtain v where v_in1: v  to_V `  (fset ` A_of ` (𝒮 - 𝒮'))
        and v_in2: v  to_V `  (fset ` A_of ` 𝒮') by blast
      obtain 𝒞 where C_in: 𝒞  𝒮 - 𝒮' and v_in_C: v  to_V ` (fset (A_of 𝒞))
        using v_in1 by blast
      obtain a where C_is1: 𝒞 = Pair bot {|a|}
        using C_in unfolding 𝒮_def ℰ_from_def by blast
      then have v_is: v = to_V a
        using v_in_C by simp
      obtain 𝒞' where C'_in: 𝒞'  𝒮' and v_in_C': v  to_V ` (fset (A_of 𝒞'))
        using v_in2 by blast
      then obtain a' where v_is': v = to_V a' and a'_in: a'  fset (A_of 𝒞')
        by blast
      consider (J) 𝒞'  𝒮𝒥 | (E') 𝒞'  𝒮'
        using C'_in 𝒮'_def by blast
      then show False
      proof cases
        case J
        then have to_V ` (fset (A_of 𝒞'))  (to_V `  (fset ` A_of ` 𝒮𝒥))
          by blast
        then have to_V ` (fset (A_of 𝒞))  (to_V `  (fset ` A_of ` 𝒮𝒥))
          using C_is1 v_in_C' v_is by auto
        then have 𝒞  𝒮'
          unfolding 𝒮'_def using C_in by blast
        then show False
          using C_in by blast
      next
        case E'
        then consider (a) 𝒞' = Pair bot {|a|} | (nega) 𝒞' = Pair bot {|neg a|}
          unfolding 𝒮'_def 𝒮_def ℰ_from_def using v_in_C' v_is
            AF.sel(2) IntE empty_iff fset_simps(1) fset_simps(2) image_iff insert_iff
            mem_Collect_eq neg.simps(1) neg.simps(2) to_V.elims
          by (smt (verit, del_insts))
        then show False
        proof cases
          case a
          then show ?thesis
            using E' a_in_ℰ Enabled equiv_ℰ_enabled_𝒩 C_in C_is1 unfolding 𝒮_def 𝒮'_def
            by blast
        next
          case nega
          have 𝒞'  ℰ_from 𝒩
            using E' unfolding 𝒮'_def 𝒮_def by auto
          moreover have 𝒞  ℰ_from 𝒩
            using C_in unfolding 𝒮_def by auto
          ultimately show ?thesis
            using a_in_ℰ nega C_is1 Enabled equiv_ℰ_enabled_𝒩 by blast
        qed
      qed
    qed
    then have empty_inter:  (atoms ` (AF_proj_to_formula_set (𝒮 - 𝒮'))) 
       (atoms ` (AF_proj_to_formula_set 𝒮')) = {}
      using atoms_simp proj_S' prop_proj_distrib prop_proj_sub
      by (smt (verit, ccfv_threshold) S_sub Un_subset_iff 𝒮 = 𝒮 - 𝒮'  𝒮' proj_prop_J'
        prop_proj_ℰ_from)
    have sat_rest: sat (AF_proj_to_formula_set (𝒮 - 𝒮'))
      using E_sat unfolding 𝒮'_def 𝒮_def AF_proj_to_formula_set_def
        propositional_projection_def sat_def by blast
    have S'_unsat: J. ¬ J p2 𝒮'
      using unsat_AF_simp[OF _ sat_rest empty_inter] S_unsat equiv_prop_entail2_sema2 S_is
        val_from_interp unfolding sat_def by metis
    have ex_fin_Js: Js. 𝒮𝒥 = 𝒥'_of ` Js  (JJs. enabled_set 𝒩 J)  finite Js
      using finite_subset_with_prop[OF ex_Js S_fin 𝒮𝒥_def] .
    then obtain Js where Js_fin: finite Js and Js_enab: JJs. enabled_set 𝒩 J and
      Js_is: 𝒥'_of ` Js = 𝒮𝒥
      by blast

    have fin_inter: finite ((fset ` A_of ` 𝒮𝒥)  (fset ` A_of ` 𝒩))
    proof
      have finite ((fset ` A_of ` 𝒮𝒥))
        unfolding 𝒮𝒥_def using S_fin image_Int_subset by simp
      then show (finite ((fset ` A_of ` 𝒮𝒥)))  (finite ( (fset ` A_of ` 𝒩)))
        by auto
    qed
    have a((fset ` A_of ` 𝒩)). 𝒞𝒩. a  fset (A_of 𝒞)
      by blast
    then obtain f where f_def: a((fset ` A_of ` 𝒩)). f a  𝒩  a  fset (A_of (f a))
      by metis
    define 𝒩𝒥 where 𝒩𝒥 = (f ` ((fset ` A_of ` 𝒮𝒥)  (fset ` A_of ` 𝒩)))
    have nj_fin: finite 𝒩𝒥
      unfolding 𝒩𝒥_def using fin_inter by blast
    have nj_sub: 𝒩𝒥  𝒩
      unfolding 𝒩𝒥_def using f_def by blast
    have nj_as: (a((fset ` A_of ` 𝒮𝒥))((fset ` A_of ` 𝒩)).
      a  (fset ` A_of ` 𝒩𝒥))
      unfolding 𝒩𝒥_def using f_def by fast

    define ℳ' where ℳ' = {ℳ'_of J |J. J  Js}
    define 𝒩' where  𝒩' = {𝒩'_of J |J. J  Js}  𝒩𝒥
    then have ℳ'  
      unfolding ℳ'_def using fsets_from_J Js_enab by fast
    moreover have 𝒩'  𝒩
      unfolding 𝒩'_def using fsets_from_J Js_enab nj_sub by fast
    moreover have finite ℳ'
      unfolding ℳ'_def using fsets_from_J Js_fin Js_enab by auto
    moreover have finite 𝒩'
      unfolding 𝒩'_def using fsets_from_J Js_fin Js_enab nj_fin by auto
    moreover have ℳ' ⊨sAF 𝒩' unfolding AF_entails_sound_def
    proof (rule allI, rule impI)
      fix J
      assume enab_N': enabled_set 𝒩' J
      then have J p2 ℰ_from 𝒩'
        using equiv_ℰ_enabled_𝒩 by auto
      moreover have 𝒮'  ℰ_from 𝒩'
        proof
          fix 𝒞
          assume C_in: 𝒞  𝒮'
          then obtain a where C_is: 𝒞 = Pair bot {|neg a|}
            unfolding 𝒮'_def 𝒮_def ℰ_from_def by blast
          then have neg a  (fset ` A_of ` 𝒮')
            using C_in using image_iff by fastforce
          then have a_in_SJ: a  (fset ` A_of ` 𝒮𝒥)
            using a_from_E_to_J by presburger
          have 𝒞'𝒩. a  fset (A_of 𝒞')
            using C_is C_in unfolding 𝒮'_def 𝒮_def by (smt (verit, ccfv_threshold)
              AF.sel(2) IntE J'_is ℰ_from_def a_in_ℰ bot_fset.rep_eq empty_iff equiv_ℰ_enabled_𝒩
              finsert.rep_eq insert_iff mem_Collect_eq to_V.elims to_V_neg)
          then have a  (fset ` A_of ` 𝒩)
            by blast
          then have a  (fset ` A_of ` 𝒩')
            using nj_as a_in_SJ unfolding 𝒩'_def by simp
          then show 𝒞  ℰ_from 𝒩'
            using C_is unfolding ℰ_from_def by blast
        qed
      ultimately have J p2 𝒮'
        unfolding 𝒮'_def 𝒮_def using subset_model_p2 by (metis (no_types, lifting))
      then have ¬ J p2 𝒮𝒥
        using subset_not_model S'_unsat unfolding 𝒮'_def by blast
      then have  J'Js. fset (A_of (𝒥'_of J'))  total_strip J
        unfolding propositional_model2_def 𝒮𝒥_def propositional_projection_def
          enabled_projection_def using Js_is
        by (smt (verit) Collect_cong Set.empty_def 𝒮𝒥_def enabled_def image_iff mem_Collect_eq)
      then obtain J' where J'_in: J'  Js and A_of_J'_in: fset (A_of (𝒥'_of J'))  total_strip J
        by blast
      then have enab_nj': enabled_set 𝒩 J'
        using Js_enab by blast
      then have sound_cons.entails_neg (Pos ` (ℳ'_of J' projJ J') 
        fml_ext ` (fset (A_of (𝒥'_of J')))) (Pos ` F_of ` 𝒩'_of J')
        using fsets_from_J by auto
      moreover have (ℳ'_of J') projJ J'  (ℳ'_of J') projJ J
      proof -
        have 𝒞  ℳ'_of J'  enabled 𝒞 J'  enabled 𝒞 J for 𝒞
        proof -
          assume C_in: 𝒞  ℳ'_of J' and
            enabled 𝒞 J'
          then have fset (A_of 𝒞)  fset (A_of (𝒥'_of J'))
            using fsets_from_J[OF enab_nj'] by blast
          then show enabled 𝒞 J
            using A_of_J'_in unfolding enabled_def by auto
        qed
        then have (𝒞  ℳ'_of J'  enabled 𝒞 J')  (𝒞  ℳ'_of J'  enabled 𝒞 J) for 𝒞
          by (smt (verit, ccfv_threshold))
        then have {𝒞. 𝒞  ℳ'_of J'  enabled 𝒞 J'}  {𝒞. 𝒞  ℳ'_of J'  enabled 𝒞 J}
          by blast
        then show (ℳ'_of J') projJ J'  (ℳ'_of J') projJ J
          unfolding enabled_projection_def by blast
      qed
      ultimately have entails_one:  sound_cons.entails_neg
        (Pos ` (ℳ'_of J' projJ J)  fml_ext ` (fset (A_of (𝒥'_of J')))) (Pos ` F_of ` 𝒩'_of J')
        using sound_cons.entails_subsets
        by (smt (verit, ccfv_SIG) Un_absorb1 Un_assoc Un_left_commute image_Un
          neg_ext_sound_cons_rel.entails_subsets subset_refl sup.cobounded1)
      have subs_MJ: Pos ` (ℳ'_of J' projJ J) 
        fml_ext ` (fset (A_of (𝒥'_of J')))  Pos ` (ℳ' projJ J)  fml_ext ` (total_strip J)
        using J'_in A_of_J'_in using enabled_projection_def unfolding ℳ'_def by auto
      have subs_N: Pos ` F_of ` (𝒩'_of J')  Pos ` F_of ` 𝒩'
        using J'_in unfolding 𝒩'_def by blast
      show sound_cons.entails_neg (fml_ext ` total_strip J  Pos ` (ℳ' projJ J))
        (Pos ` F_of ` 𝒩')
        using neg_ext_sound_cons_rel.entails_subsets[OF subs_MJ subs_N entails_one]
        by (simp add: Un_commute)
    qed

    ultimately
    show ℳ' 𝒩'. ℳ'    𝒩'  𝒩  finite ℳ'  finite 𝒩'  ℳ' ⊨sAF 𝒩'
      by blast
  qed
qed
  
interpretation AF_sound_cons_rel: consequence_relation "to_AF bot" AF_entails_sound
  by (rule AF_ext_sound_cons_rel)

lemma f_of_to_AF [simp]: F_of ` to_AF ` N = N
  unfolding to_AF_def by force

lemma to_AF_proj_J [simp]: to_AF ` M projJ J = M
  unfolding to_AF_def enabled_projection_def enabled_def by force

lemma enabled_to_AF_set [simp]: enabled_set (to_AF ` N) J
  unfolding enabled_set_def enabled_def to_AF_def by simp

lemma pos_not_pos_empty [simp]: {to_V C |C. C  Pos ` N  ¬ is_Pos C} = {}
  by auto
    
lemma pos_not_pos_simp [simp]:
  {to_V C |C. C  U  Pos ` M  ¬ is_Pos C} = {to_V C |C. C  U  ¬ is_Pos C}
  by auto

lemma pos_pos_simp [simp]: {to_V C |C. C  Pos ` F_of ` N  is_Pos C} = F_of ` N
  by force 

lemma proj_F_of [simp]: {C. F_of C  M} projJ J = M
proof (intro equalityI subsetI)
  fix x
  assume x_in: x  {C. F_of C  M} projJ J
  define C::"('f,'v) AF" where C = to_AF x
  then show x  M 
    using x_in unfolding enabled_projection_def enabled_def to_AF_def by auto 
next
  fix x
  assume x_in: x  M
  define C::"('f,'v) AF" where C = to_AF x
  then show x   {C. F_of C  M} projJ J 
    using x_in unfolding enabled_projection_def enabled_def to_AF_def
    by (metis (mono_tags, lifting) AF.sel(1) AF.sel(2) bot_fset.rep_eq empty_subsetI mem_Collect_eq)
qed 

lemma f_of_F_of [simp]: F_of ` {C. F_of C  M} = M
proof (intro equalityI subsetI)
  fix x
  assume x_in: x  F_of ` {C. F_of C  M}
  define C where C = to_AF x
  then show x  M
    using x_in by blast 
next
  fix x
  assume x_in: x  M
  define C where C = to_AF x
  then show x  F_of ` {C. F_of C  M}
    using x_in by (smt (z3) AF.sel(1) imageI mem_Collect_eq) 
qed
  
lemma set_on_union_triple_split: {f C |C. C  M  N  g J  l C J} = {f C |C. C  M  l C J} 
  {f C |C. C  N  l C J}  {f C |C. C  g J  l C J}
  by blast 

lemma not_enabled_enabled_empty [simp]:
  {F_of C |C. C  {C. F_of C  Q'  ¬ enabled C J}  enabled C J} = {}
proof (intro equalityI subsetI)
  fix x
  assume x_in: x  {F_of C |C. C  {C. F_of C  Q'  ¬ enabled C J}  enabled C J}
  then obtain C where F_of C = x and c_in: C  {C. F_of C  Q'  ¬ enabled C J} and
    enab_c: enabled C J
    by blast
  then have ¬ enabled C J using c_in by blast 
  then have False using enab_c by auto 
  then show x  {} by auto 
qed auto

lemma f_of_simp_enabled [simp]: {F_of C |C. F_of C  M  enabled C J} = M
  unfolding enabled_def
  by (smt (verit, best) AF.sel(1) AF.sel(2) bot_fset.rep_eq empty_subsetI mem_Collect_eq subsetI
      subset_antisym)

lemma f_of_enabled_simp [simp]: F_of ` {C. F_of C  M  enabled C J} = M
proof -
  have F_of ` {C. F_of C  M  enabled C J} = {F_of C |C. F_of C  M  enabled C J}
    by blast 
  then show ?thesis by simp
qed

(* Splitting report Lemma 6, 1/2 *)
lemma (to_AF ` M AF to_AF ` N)  (M  N)
  unfolding AF_entails_def by simp

sublocale ext_cons_rel_std: consequence_relation "Pos (to_AF bot)" AF_cons_rel.entails_neg
  using AF_cons_rel.ext_cons_rel .

sublocale sound_cons_rel: consequence_relation "Pos bot" sound_cons.entails_neg
  using sound_cons.ext_cons_rel .

lemma pos_in_pos_simp [simp]: {C. Pos C  Pos ` N} = N by auto
lemma neg_not_in_pos_simp [simp]: {C. Neg C  Pos ` N} = {} by auto
lemma neg_in_pos_simp [simp]: {C. Neg C  P  Neg C  Pos ` M} = {C. Neg C  P} by blast
lemma pos_in_pos_partial_simp [simp]: {C. Pos C  P  Pos C  Pos ` M} = {C. Pos C  P}  M by auto
    
(* Splitting report Lemma 6, 2/2 *)
lemma (to_AF ` M ⊨sAF to_AF ` N)  (M ⊨s N)
proof -
  {
    fix M N
    assume m_to_n: M ⊨s N
    have to_AF ` M ⊨sAF to_AF ` N
      unfolding AF_entails_sound_def sound_cons.entails_neg_def 
    proof (rule allI, rule impI)
      fix J
      have {C. Pos C  fml_ext ` total_strip J}  M ⊨s N  {C. Neg C  fml_ext ` total_strip J}
      proof -
        have m_in: M  {to_V C |C. (C  fml_ext ` total_strip J  C  Pos ` M)  is_Pos C}
          by force
        show {C. Pos C  fml_ext ` total_strip J}  M ⊨s
          N  {C. Neg C  fml_ext ` total_strip J}
          using m_to_n m_in by (meson Un_subset_iff sound_cons.entails_subsets subset_refl)
      qed
      then show {C. Pos C  fml_ext ` total_strip J  Pos ` (to_AF ` M projJ J)}  
        {C. Neg C  Pos ` F_of ` to_AF ` N} ⊨s {C. Pos C  Pos ` F_of ` to_AF ` N} 
        {C. Neg C  fml_ext ` total_strip J  Pos ` (to_AF ` M projJ J)}
        by simp
    qed
  } moreover {
    fix M N
    assume m_af_entails_n: to_AF ` M ⊨sAF to_AF ` N
    have M  M'  N  N'  M'  N' = UNIV  M' ⊨s N' for M' N'
    proof - 
      fix M' N'
      assume m_in: M  M' and
        n_in: N  N' and
        union_mnp_is_univ: M'  N' = UNIV
      {
        assume M'  N'  {}
        then have M' ⊨s N'
          using sound_cons.entails_reflexive sound_cons.entails_subsets
          by (meson Int_lower1 Int_lower2 sound_cons.entails_cond_reflexive)
      }
      moreover {
        assume empty_inter_mp_np: M'  N' = {}
        define Jpos where Jpos = {v. to_V (fml_ext v)  M'  is_Pos v}
        define Jneg where Jneg = {v |v. to_V (fml_ext v)  M'  ¬ is_Pos v}
        have total_J_pos_neg: to_V ` (Jpos  Jneg) = UNIV
        proof
          show to_V ` (Jpos  Jneg)  UNIV by simp
        next
          show UNIV  to_V ` (Jpos  Jneg)
          proof
            fix v::"'v"
            define v_p where v_p = Pos v
            define v_n where v_n = Neg v
            have v_p  Jpos  v_n  Jneg
              unfolding v_p_def v_n_def Jpos_def Jneg_def by simp
            then show v  to_V ` (Jpos  Jneg)
              unfolding v_p_def v_n_def by force
          qed
        qed
        define Jstrip where Jstrip = Jpos  Jneg
        have interp_Jstrip: is_interpretation Jstrip
          unfolding is_interpretation_def
        proof (rule ballI, rule ballI, rule impI, rule ccontr)
          fix v1 v2
          assume v1_in: v1  Jstrip and
            v2_in: v2  Jstrip and
            v12_eq: to_V v1 = to_V v2 and
            contra: v1  v2
          have pos_neg_cases: (v1  Jpos  v2  Jneg)  (v1  Jneg  v2  Jpos)
            using v1_in v2_in contra unfolding Jstrip_def Jpos_def Jneg_def
            by (smt (z3) Collect_mono_iff Collect_subset Un_def is_Neg_to_V is_Pos_to_V v12_eq)
          then have to_V (fml_ext v1)  to_V (fml_ext v2)
            using empty_inter_mp_np unfolding Jneg_def Jpos_def by auto 
          then show False
            using fml_ext_preserves_val[OF v12_eq] by blast 
        qed
        then obtain Jinterp where Jinterp_is: "strip Jinterp = Jstrip"
          by (metis Rep_propositional_interpretation_cases mem_Collect_eq)
        have total Jinterp
          unfolding total_def
        proof
          fix v
          define v_p::"'v sign" where "v_p = Pos v"
          define v_n::"'v sign" where "v_n = Neg v"
          have "v_p  Jpos  v_n  Jneg"
            unfolding v_p_def v_n_def Jpos_def Jneg_def by simp
          then have "v_p  Jstrip  v_n  Jstrip"
            unfolding Jstrip_def by fast
          then have v_p J Jinterp  v_n J Jinterp
            using Jinterp_is unfolding belong_to_def by simp
          then show vJ. vJ J Jinterp  to_V vJ = v
            using v_p_def v_n_def by auto
        qed
        then obtain Jtotal where Jtotal_is: "total_strip Jtotal = Jstrip"
          using Jinterp_is by (metis Rep_total_interpretation_cases mem_Collect_eq)
        have enabled_set (to_AF ` N) Jtotal
          unfolding enabled_set_def to_AF_def enabled_def using Jtotal_is Jstrip_def Jneg_def
          by simp
        then have fml_ext ` total_strip Jtotal  Pos ` M ⊨s Pos ` N
          using m_af_entails_n unfolding AF_entails_sound_def by simp
        then have entails_m_n_jtot: {C. Pos C  fml_ext ` total_strip Jtotal}  M  ⊨s
           N  {C. Neg C  fml_ext ` total_strip Jtotal}
          unfolding sound_cons.entails_neg_def by simp
        have {C. Pos C  fml_ext ` total_strip Jtotal}  M'
          unfolding Jtotal_is Jstrip_def Jpos_def Jneg_def
          by (smt (verit, ccfv_threshold) UnE fml_ext_preserves_sign imageE is_Pos.simps(1)
            mem_Collect_eq subsetI to_V.simps(1))
        then have sub_mp: {C. Pos C  fml_ext ` total_strip Jtotal}  M  M'
          using m_in by simp
        have {C. Neg C  fml_ext ` total_strip Jtotal}  N'
          unfolding Jtotal_is Jstrip_def Jpos_def Jneg_def
        proof -
          have {C. Neg C  fml_ext ` {v. to_V (fml_ext v)  M'  is_Pos v}} = {}
            using fml_ext_preserves_sign is_Pos.simps(1)
            by (smt (verit, ccfv_SIG) empty_iff imageE is_Pos.simps(2) mem_Collect_eq subsetI
              subset_antisym)
          moreover have {C. Neg C  fml_ext ` {v |v. to_V (fml_ext v)  M'  ¬ is_Pos v}}  N'
            using fml_ext_preserves_sign is_Pos.simps(2)
          proof -
            have {C. Neg C  fml_ext ` {v |v. to_V (fml_ext v)  M'  ¬ is_Pos v}} =
              {C. Neg C  fml_ext ` {v |v. to_V (fml_ext v)  N'  ¬ is_Pos v}}
              using empty_inter_mp_np union_mnp_is_univ by auto 
            also have {C. Neg C  fml_ext ` {v |v. to_V (fml_ext v)  N'  ¬ is_Pos v}}  N'
              using fml_ext_preserves_sign is_Pos.simps(2)
              by (smt (verit, best) imageE mem_Collect_eq subsetI to_V.simps(2))      
            finally show {C. Neg C  fml_ext ` {v |v. to_V (fml_ext v)  M'  ¬ is_Pos v}}  N' .
          qed
          ultimately show {C. Neg C  fml_ext `
            ({v. to_V (fml_ext v)  M'  is_Pos v} 
            {v |v. to_V (fml_ext v)  M'  ¬ is_Pos v})}
             N'
            by blast
        qed
        then have sub_np: N  {C. Neg C  fml_ext ` total_strip Jtotal}  N'
          using n_in by blast
        have M' ⊨s N'
          using sound_cons.entails_subsets[OF sub_mp sub_np entails_m_n_jtot] .
      }
      ultimately show "M' ⊨s N'" by blast
    qed
    then have supsets_entail: M' N'. (M'  M  N'  N  M'  N' = UNIV)  M' ⊨s N'
      by clarsimp
    then have M ⊨s N
      using sound_cons.entails_supsets by simp
  }
  ultimately show (to_AF ` M ⊨sAF to_AF ` N)  (M ⊨s N)
    by (smt (verit, best))
qed

lemma strong_entails_bot_cases: 𝒩  {AF.Pair bot A} ⊨sAF {AF.Pair bot B} 
  ( J. fset B  total_strip J 
    (fml_ext ` total_strip J  Pos ` (𝒩 projJ J)) ⊨s {Pos bot}  fset A  total_strip J)
proof -
  assume 𝒩  {AF.Pair bot A} ⊨sAF {AF.Pair bot B}
  then have fset B  total_strip J 
              (fml_ext ` total_strip J  Pos ` (𝒩 projJ J)  Pos ` ({AF.Pair bot A} projJ J))
              ⊨s {Pos bot}
    for J
    unfolding AF_entails_sound_def
    by (metis (no_types, lifting) AF.sel(1) AF.sel(2) distrib_proj_singleton enabled_def
         enabled_set_def image_Un image_empty image_insert singletonD sup_assoc)
  then have fset B  total_strip J 
        ((fml_ext ` total_strip J)  Pos ` (𝒩 projJ J)) ⊨s {Pos bot}  enabled (AF.Pair bot A) J
    for J 
    by (smt (verit, ccfv_SIG) enabled_projection_def ex_in_conv image_empty
         mem_Collect_eq singletonD sup_bot_right)
  then show ?thesis
    by (simp add: enabled_def)
qed

lemma strong_entails_bot_cases_Union:
  𝒩   ⊨sAF {AF.Pair bot B}  ( x  . F_of x = bot) 
    ( J. fset B  total_strip J 
      (fml_ext ` total_strip J  Pos ` (𝒩 projJ J)) ⊨s {Pos bot} 
      ( A  A_of ` . fset A  total_strip J))
proof -
  assume 𝒩_union_ℳ_entails_Pair_bot_B: 𝒩   ⊨sAF {AF.Pair bot B} and
          x  . F_of x = bot
  then show ?thesis
  proof (cases  = {})
    case True
    then show ?thesis
      using AF_entails_sound_def 𝒩_union_ℳ_entails_Pair_bot_B enabled_def enabled_set_def
      by auto
  next
    case False
    then show ?thesis
    proof (intro allI impI)
      fix J
      assume B_in_J: fset B  total_strip J
      then show (fml_ext ` total_strip J  Pos ` (𝒩 projJ J)) ⊨s {Pos bot} 
                    ( A  A_of ` . fset A  total_strip J)
      proof (cases  A  A_of ` . fset A  total_strip J)
        case True
        then show ?thesis
          by blast
      next
        case False
        then have  A  A_of ` . ¬ fset A  total_strip J
          by blast
        then have  projJ J = {}
          by (simp add: enabled_def enabled_projection_def)
        then show ?thesis
          using 𝒩_union_ℳ_entails_Pair_bot_B[unfolded AF_entails_sound_def, rule_format]
                B_in_J distrib_proj enabled_def enabled_set_def
          by fastforce
      qed
    qed
  qed
qed


lemma AF_entails_sound_right_disjunctive: ( 𝒞'  A.  ⊨sAF {𝒞'})   ⊨sAF A
proof -
  assume  𝒞'  A.  ⊨sAF {𝒞'}
  then obtain 𝒞' where  ⊨sAF {𝒞'} and
                       𝒞'  A
    by blast
  then show  ⊨sAF A
    by (meson AF_sound_cons_rel.entails_subsets empty_subsetI insert_subset subset_refl)
qed

subsection ‹Local saturation›

text ‹ To fully capture completeness for splitting, we need to use weaker notions of saturation and
 fairness.›

(* Report definition 23 *)
definition locally_saturated :: ('f, 'v) AF set  bool where
  locally_saturated 𝒩 
    to_AF bot  𝒩 
    ( J :: 'v total_interpretation. J p 𝒩  saturated (𝒩 projJ J))
    (* NOTE: in the paper, the propositional projection is explicit.
     * In our case, it is hidden within the definition for @{const propositional_model}. *)

(* Report definition 26 *)
definition locally_fair :: ('f, 'v) AF set infinite_llist  bool where
  locally_fair 𝒩i 
     ( i. to_AF bot  llnth 𝒩i i)
    ( J :: 'v total_interpretation. J p lim_inf 𝒩i 
        Inf_from (lim_inf 𝒩i projJ J)  ( i. RedI (llnth 𝒩i i projJ J)))

end (* locale calculus_with_annotated_consrel *)

locale strong_statically_complete_annotated_calculus =  
  calculus_with_annotated_consrel  bot Inf entails entails_sound RedI RedF fml asn
  + S_calculus: calculus "to_AF bot" SInf AF_entails SRedI SRedF
  for
    bot :: "'f" and
    Inf :: 'f inference set and
    entails :: "'f set  'f set  bool" (infix "" 50) and
    entails_sound :: "'f set  'f set  bool" (infix "⊨s" 50) and
    RedI :: "'f set  'f inference set" and
    RedF :: "'f set  'f set" and
    fml :: 'v :: countable  'f and 
    asn :: 'f sign  'v sign set and
    SInf :: "('f, 'v) AF inference set" and
    SRedI :: "('f, 'v) AF set  ('f, 'v) AF inference set" and
    SRedF :: "('f, 'v) AF set  ('f, 'v) AF set"
  + assumes
    strong_static_completeness: locally_saturated 𝒩  𝒩 AF {to_AF bot}  to_AF bot  𝒩

locale strong_dynamically_complete_annotated_calculus =  
  calculus_with_annotated_consrel  bot Inf entails entails_sound RedI RedF fml asn
  + S_calculus: calculus "to_AF bot" SInf AF_entails SRedI SRedF
  for
    bot :: "'f" and
    Inf :: 'f inference set and
    entails :: "'f set  'f set  bool" (infix "" 50) and
    entails_sound :: "'f set  'f set  bool" (infix "⊨s" 50) and
    RedI :: "'f set  'f inference set" and
    RedF :: "'f set  'f set" and
    fml :: 'v :: countable  'f and 
    asn :: 'f sign  'v sign set and
    SInf :: "('f, 'v) AF inference set" and
    SRedI :: "('f, 'v) AF set  ('f, 'v) AF inference set" and
    SRedF :: "('f, 'v) AF set  ('f, 'v) AF set"
  + assumes
    strong_dynamic_completeness: is_derivation S_calculus.derive 𝒩i  locally_fair 𝒩i 
      llhd 𝒩i AF {to_AF bot}  i. to_AF bot  llnth 𝒩i i


end