Theory Paraconsistency_Validity_Infinite

(* Anders Schlichtkrull, DTU Compute, Denmark *)

theory Paraconsistency_Validity_Infinite imports Paraconsistency
  abbrevs
    "Truth" = ""
    and
    "Falsity" = ""
    and
    "Neg'" = "¬"
    and
    "Con'" = ""
    and
    "Eql" = ""
    and
    "Eql'" = ""
    and
    "Dis'" = ""
    and
    "Imp" = ""
    and
    "Imp'" = ""
    and
    "Box" = ""
    and
    "Neg" = ""
    and
    "Con" = ""
    and
    "Dis" = ""
    and
    "Cla" = "Δ"
    and
    "Nab" = ""
    and
    "CON" = "[]"
    and
    "DIS" = "[]"
    and
    "NAB" = "[]"
    and
    "ExiEql" = "[=]"
begin

text
‹
The details about the definitions, lemmas and theorems are described in an article in the
Post-proceedings of the 24th International Conference on Types for Proofs and Programs (TYPES 2018).
›

section ‹Notation›

notation Pro ("_" [39] 39)
notation Truth ("")
notation Neg' ("¬ _" [40] 40)
notation Con' (infixr "" 35)
notation Eql (infixr "" 25)
notation Eql' (infixr "" 25)
notation Falsity ("")
notation Dis' (infixr "" 30) 
notation Imp (infixr "" 25) 
notation Imp' (infixr "" 25)
notation Box (" _" [40] 40) 
notation Neg (" _" [40] 40)
notation Con (infixr "" 35) 
notation Dis (infixr "" 30)
notation Cla ("Δ _" [40] 40) 
notation Nab (" _" [40] 40)
abbreviation DetTrue :: tv ("") where "  Det True"
abbreviation DetFalse :: tv ("") where "  Det False"
notation Indet ("_" [39] 39)

text 
‹
Strategy: We define a formula that is valid in the sets {0..<1}, {0..<2}, ..., {0..<n-1} but is
not valid in the set {0..<n}
›

section ‹Injections From Sets to Sets›

text 
‹
We define the notion of an injection from a set X to a set Y 
›

definition inj_from_to :: "('a  'b)  'a set  'b set  bool" where
  "inj_from_to f X Y  inj_on f X  f ` X  Y"

lemma bij_betw_inj_from_to: "bij_betw f X Y  inj_from_to f X Y"
  unfolding bij_betw_def inj_from_to_def by simp

text 
‹
Special lemma for finite cardinality only
›

lemma inj_from_to_if_card:
  assumes "card X  card Y"
  assumes "finite X"
  shows "f. inj_from_to f X Y"
  unfolding inj_from_to_def
  by (metis assms card_image card_le_inj card_subset_eq obtain_subset_with_card_n order_refl)

section ‹Extension of Paraconsistency Theory›

text 
‹
The Paraconsistency theory is extended with abbreviation is_det› and a number of lemmas that are 
or generalizations of previous lemmas
›

abbreviation is_det :: "tv  bool" where "is_det tv  ¬ is_indet tv"

theorem valid_iff_valid_in:
  assumes "card U  card (props p)"
  shows "valid p  valid_in U p"
  using assms valid_in_valid valid_valid_in by blast

text 
‹
Generalization of change_tv_injection›

lemma change_tv_injection_on:
  assumes "inj_on f U"
  shows "inj_on (change_tv f) (domain U)"
proof
  fix x y
  assume "x  domain U" "y  domain U" "change_tv f x = change_tv f y"
  then show "x = y"
    unfolding domain_def using assms inj_onD by (cases x; cases y) auto
qed

text 
‹
Similar to change_tv_injection_on›

lemma change_tv_injection_from_to:
  assumes "inj_from_to f U W"
  shows "inj_from_to (change_tv f) (domain U) (domain W)"
  unfolding inj_from_to_def
proof
  show "inj_on (change_tv f) (domain U)"
    using assms change_tv_injection_on unfolding inj_from_to_def by blast
next
  show "change_tv f ` domain U  domain W"
  proof
    fix x
    assume "x  change_tv f ` domain U"
    then show "x  domain W"
      unfolding domain_def image_def
      using assms inj_from_to_def[of f U W]
      by (cases x) auto
  qed
qed

text 
‹
Similar to eval_change_inj_on›

lemma change_tv_surj_on:
  assumes "f ` U = W"
  shows "(change_tv f) ` (domain U) = (domain W)"
proof
  show "change_tv f ` domain U  domain W"
  proof
    fix x
    assume "x  change_tv f ` domain U"
    then show "x  domain W"
    proof
      fix x'
      assume "x = change_tv f x'" "x'  domain U"
      then show "x  domain W"
        unfolding domain_def using assms by fastforce
    qed
  qed
next
  show "domain W  change_tv f ` domain U"
  proof
    fix x
    assume "x  domain W"
    then show "x  change_tv f ` domain U"
      unfolding domain_def using assms image_iff by fastforce
  qed
qed

text 
‹
Similar to eval_change_inj_on›

lemma change_tv_bij_betw:
  assumes "bij_betw f U W"
  shows "bij_betw (change_tv f) (domain U) (domain W)"
  using assms change_tv_injection_on change_tv_surj_on unfolding bij_betw_def by simp

text 
‹
Generalization of eval_change›

lemma eval_change_inj_on:
  assumes "inj_on f U"
  assumes "range i  domain U"
  shows "eval (change_int f i) p = change_tv f (eval i p)"
proof (induct p)
  fix p
  assume "eval (change_int f i) p = change_tv f (eval i p)"
  then have "eval_neg (eval (change_int f i) p) = eval_neg (change_tv f (eval i p))"
    by simp
  then have "eval_neg (eval (change_int f i) p) = change_tv f (eval_neg (eval i p))"
    by (cases "eval i p") (simp_all add: case_bool_if)
  then show "eval (change_int f i) (¬ p) = change_tv f (eval i (¬ p))"
    by simp
next
  fix p1 p2
  assume ih1: "eval (change_int f i) p1 = change_tv f (eval i p1)"
  assume ih2: "eval (change_int f i) p2 = change_tv f (eval i p2)"
  show "eval (change_int f i) (p1  p2) = change_tv f (eval i (p1  p2))"
    using assms ih1 ih2 change_tv.simps(1) change_tv_injection_on eval.simps(2) eval.simps(4)
      inj_onD ranges by metis
next
  fix p1 p2
  assume ih1: "eval (change_int f i) p1 = change_tv f (eval i p1)"
  assume ih2: "eval (change_int f i) p2 = change_tv f (eval i p2)"
  have "Det (eval (change_int f i) p1 = eval (change_int f i) p2) =
      Det (change_tv f (eval i p1) = change_tv f (eval i p2))"
    using ih1 ih2 by simp
  also have "... = Det ((eval i p1) = (eval i p2))"
  proof -
    have "inj_on (change_tv f) (domain U)"
      using assms(1) change_tv_injection_on by simp
    then show ?thesis
      using assms(2) ranges by (simp add: inj_on_eq_iff)
  qed
  also have "... = change_tv f (Det (eval i p1 = eval i p2))"
    by simp
  finally show "eval (change_int f i) (p1  p2) = change_tv f (eval i (p1  p2))"
    by simp
next
  fix p1 p2
  assume ih1: "eval (change_int f i) p1 = change_tv f (eval i p1)"
  assume ih2: "eval (change_int f i) p2 = change_tv f (eval i p2)"
  show "eval (change_int f i) (p1  p2) = change_tv f (eval i (p1  p2))"
    using assms ih1 ih2 inj_on_eq_iff change_tv.simps(1) change_tv_injection_on eval_equality
      eval_negation ranges by smt
qed (simp_all add: change_int_def)

section ‹Logics of Equal Cardinality Are Equal›

text 
‹
We prove that validity in a set depends only on the cardinality of the set
›

lemma inj_from_to_valid_in:
  assumes "inj_from_to f W U"
  assumes "valid_in U p"
  shows "valid_in W p"
  unfolding valid_in_def proof (rule, rule)
  fix i :: "char list  tv"
  assume a: "range i  domain W"
  from assms have valid_p: "i. range i  domain U  eval i p = "
    unfolding valid_in_def by simp
  have "range (change_int f i)  domain U"
  proof
    fix x
    assume "x  range (change_int f i)"
    then obtain xa where xa: "change_int f i xa = x"
      by blast
    have "inj_from_to (change_tv f) (domain W) (domain U)"
      using change_tv_injection_from_to assms by simp
    then have "(change_tv f) (i xa)  domain U"
      using a by (metis inj_from_to_def image_eqI range_eqI subsetCE)
    then show "x  domain U"
      using xa change_int_def by simp
  qed
  then have "eval (change_int f i) p = "
    using valid_p by simp
  then have "eval (change_int f i) p = "
    by simp
  then have "change_tv f (eval i p) = "
    using a assms(1) eval_change_inj_on unfolding inj_from_to_def by metis
  then show "eval i p = "
    using change_tv.elims tv.distinct(1) by fast
qed

corollary
  assumes "inj_from_to f U W"
  assumes "inj_from_to g W U"
  shows "valid_in U p  valid_in W p"
  using assms inj_from_to_valid_in by fast

lemma bij_betw_valid_in:
  assumes "bij_betw f U W"
  shows "valid_in U p  valid_in W p"
  using assms inj_from_to_valid_in bij_betw_inv bij_betw_inj_from_to by metis

theorem eql_finite_eql_card_valid_in:
  assumes "finite U  finite W"
  assumes "card U = card W"
  shows "valid_in U p  valid_in W p"
proof (cases "finite U")
  case True
  then show ?thesis
    using assms bij_betw_iff_card bij_betw_valid_in by metis
next
  case False
  then have "(f :: nat  nat. bij_betw f U UNIV)  (g :: nat  nat. bij_betw g W UNIV)"
    using assms Schroeder_Bernstein infinite_iff_countable_subset inj_Suc top_greatest by metis
  with bij_betw_valid_in show ?thesis
    by metis
qed

corollary
  assumes "U  {}"
  assumes "W  {}"
  assumes "card U = card W"
  shows "valid_in U p  valid_in W p"
  using assms eql_finite_eql_card_valid_in card_gt_0_iff by metis

theorem finite_eql_card_valid_in:
  assumes "finite U"
  assumes "finite W"
  assumes "card U = card W"
  shows "valid_in U p  valid_in W p"
  using eql_finite_eql_card_valid_in by (simp add: assms)

theorem infinite_valid_in:
  assumes "infinite U"
  assumes "infinite W"
  shows "valid_in U p  valid_in W p"
  using eql_finite_eql_card_valid_in by (simp add: assms)

section ‹Conversions Between Nats and Strings›

definition nat_of_digit :: "char  nat" where
  "nat_of_digit c =
   (if c = (CHR ''1'') then 1 else if c = (CHR ''2'') then 2 else if c = (CHR ''3'') then 3 else
    if c = (CHR ''4'') then 4 else if c = (CHR ''5'') then 5 else if c = (CHR ''6'') then 6 else
    if c = (CHR ''7'') then 7 else if c = (CHR ''8'') then 8 else if c = (CHR ''9'') then 9 else 0)"

proposition "range nat_of_digit = {0..<10}"
proof
  show "range nat_of_digit  {0..<10}"
    unfolding nat_of_digit_def by auto
next
  show "{0..<10}  range nat_of_digit"
  proof
    fix x :: nat
    assume a: "x  {0..<10}"
    show "x  range nat_of_digit"
    proof (cases "x = 0")
      case True
      then show ?thesis
        unfolding nat_of_digit_def by auto
    next
      case False
      with a show ?thesis
        unfolding nat_of_digit_def by auto
    qed
  qed
qed

lemma nat_of_digit_of_nat[simp]: "n < 10  nat_of_digit (digit_of_nat n) = n"
  unfolding digit_of_nat_def nat_of_digit_def
  by simp presburger

function nat_of_string :: "string  nat"
  where
    "nat_of_string n = (if length n  1 then nat_of_digit (last n) else
      (nat_of_string (butlast n)) * 10 + (nat_of_digit (last n)))"
  by simp_all
termination
  by (relation "measure length") simp_all

lemma nat_of_string_step:
  "nat_of_string (string_of_nat (m div 10)) * 10 + m mod 10 = nat_of_string (string_of_nat m)"
  by simp

lemma nat_of_string_of_nat: "nat_of_string (string_of_nat n) = n"
proof (induct rule: string_of_nat.induct)
  case (1 m)
  then show ?case
  proof (cases "m < 10")
    case True
    then show ?thesis
      by simp
  next
    case False
    then have "nat_of_string (string_of_nat (m div 10)) = m div 10"
      using 1 by simp
    then have "nat_of_string (string_of_nat (m div 10)) * 10 = (m div 10) * 10"
      by simp
    then have "nat_of_string (string_of_nat (m div 10)) * 10 + (m mod 10) =
        (m div 10) * 10 + (m mod 10)"
      by simp
    also have "... = m"
      by simp
    finally show ?thesis
      using nat_of_string_step by simp
  qed
qed

lemma "inj string_of_nat"
  using inj_on_inverseI nat_of_string_of_nat by metis

section ‹Derived Formula Constructors›

definition PRO :: "id list  fm list" where
  "PRO ids  map Pro ids"

definition Pro_nat :: "nat  fm" ("_1" [40] 40) where
  "n1  string_of_nat n"

definition PRO_nat :: "nat list  fm list" ("_123" [40] 40) where
  "ns123  map Pro_nat ns"

definition CON :: "fm list  fm" ("[] _" [40] 40) where
  "[] ps  foldr Con ps "

definition DIS :: "fm list  fm" ("[] _" [40] 40) where
  "[] ps  foldr Dis ps "

definition NAB :: "fm list  fm" ("[] _" [40] 40) where
  "[] ps  [] (map Nab ps)"

definition off_diagonal_product :: "'a set  'a set  ('a × 'a) set" where
  "off_diagonal_product xs ys  {(x,y). (x,y)  (xs × ys)  x  y }"

definition List_off_diagonal_product :: "'a list  'a list  ('a × 'a) list" where
  "List_off_diagonal_product xs ys  filter (λ(x,y). not_equal x y) (List.product xs ys)"

definition ExiEql :: "fm list  fm" ("[=] _" [40] 40) where
  "[=] ps  [] (map (λ(x,y). x  y) (List_off_diagonal_product ps ps))"

lemma cla_false_Imp:
  assumes "eval i a = "
  assumes "eval i b = "
  shows "eval i (a  b) = "
  using assms by simp

lemma eval_CON:
  "eval i ([] ps) = Det (p  set ps. eval i p = )"
  unfolding CON_def
  by (induct ps) simp_all

lemma eval_DIS:
  "eval i ([] ps) = Det (p  set ps. eval i p = )"
  unfolding DIS_def
proof (induct ps)
  case Nil
  then show ?case
    by simp
next
  case Cons
  with eval.simps eval_negation foldr.simps list.set_intros o_apply set_ConsD show ?case by smt
qed

lemma eval_Nab: "eval i ( p) = Det (is_indet (eval i p))"
proof (induct p)
  case (Pro x)
  then show ?case
    using string_tv.cases tv.simps(5) tv.simps(6) eval_negation
      eval.simps(2) eval.simps(4) eval.simps(5) by smt
next
  case (Neg' p)
  then show ?case
    using eval_negation by fastforce
next
  case (Eql' p1 p2)
  then show ?case
    using string_tv.cases tv.simps(5) tv.simps(6) eval_negation
      eval.simps(2) eval.simps(4) eval.simps(5) by smt
qed auto

lemma eval_NAB:
  "eval i ([] ps) = Det (p  set ps. is_indet (eval i p))"
proof (cases "pset ps. is_indet (eval i p)")
  case True
  then have "eval i ([] ps) = "
    unfolding NAB_def using eval_CON by fastforce
  then show ?thesis
    using True by simp
next
  case False
  then have "¬ (pset ps. eval i ( p) = )"
    using eval_Nab by simp
  then have "¬ (pset (map Nab ps). eval i p = )"
    by simp
  then have "eval i ([] ps) = "
    unfolding NAB_def using eval_CON[of i "(map Nab ps)"] by simp
  then show ?thesis
    using False by simp
qed

lemma eval_ExiEql:
  "eval i ([=] ps) =
    Det ((p1, p2)(off_diagonal_product (set ps) (set ps)). eval i p1 = eval i p2)"
  using eval_DIS[of i "(map (λ(x, y). x  y) (List_off_diagonal_product ps ps))"]
  unfolding off_diagonal_product_def ExiEql_def List_off_diagonal_product_def
  by auto

section ‹Pigeon Hole Formula›

definition pigeonhole_fm :: "nat  fm" where
  "pigeonhole_fm n  [] [0..<n]123  [=] [0..<n]123"

definition interp_of_id :: "nat  id  tv" where
  "interp_of_id maxi i  if (nat_of_string i) < maxi then nat_of_string i  else "

lemma interp_of_id_pigeonhole_fm_False: "eval (interp_of_id n) (pigeonhole_fm n) = "
proof -
  have all_indet: "p  set ([0..<n]123). is_indet (eval (interp_of_id n) p)"
  proof
    fix p
    assume a: "p  set ([0..<n]123)"
    show "is_indet (eval (interp_of_id n) p)"
    proof -
      from a have "p  Pro_nat ` {..<n}"
        unfolding PRO_nat_def using atLeast_upt set_map by metis
      then have "m<n. p = (m1)"
        unfolding Pro_nat_def by fast
      then show ?thesis                
        unfolding interp_of_id_def Pro_nat_def using nat_of_string_of_nat by fastforce
    qed
  qed
  then have "eval (interp_of_id n) ([] ([0..<n]123)) = "
    using eval_NAB by simp
  moreover
  have "a b. a  set (map (λn. n1) [0..<n]) 
         b  set (map (λn. n1) [0..<n])  a  b 
         eval (interp_of_id n) a = eval (interp_of_id n) b  False"
    using all_indet in_set_conv_nth length_map nat_of_string_of_nat nth_map tv.inject tv.simps(5)
      eval.simps(1)
    unfolding interp_of_id_def PRO_def PRO_nat_def Pro_nat_def
    by smt
  then have "(p1, p2)off_diagonal_product (set ([0..<n]123)) (set ([0..<n]123)).
               eval (interp_of_id n) p1  eval (interp_of_id n) p2"
    unfolding off_diagonal_product_def PRO_nat_def Pro_nat_def by blast
  then have "¬ ((p1, p2)off_diagonal_product (set ([0..<n]123)) (set ([0..<n]123)).
              eval (interp_of_id n) p1 = eval (interp_of_id n) p2)"
    by blast
  then have "eval (interp_of_id n) ([=] ([0..<n]123)) = "
    using eval_ExiEql[of "interp_of_id n" "[0..<n]123"] by simp
  ultimately
  show ?thesis
    unfolding pigeonhole_fm_def using cla_false_Imp[of "interp_of_id n"] by blast
qed

lemma range_interp_of_id: "range (interp_of_id n)  domain {0..<n}"
  unfolding interp_of_id_def domain_def by (simp add: image_subset_iff)

theorem not_valid_in_n_pigeonhole_fm: "¬ (valid_in {0..<n} (pigeonhole_fm n))"
  unfolding valid_in_def using interp_of_id_pigeonhole_fm_False[of n] range_interp_of_id[of n]
  by fastforce

theorem not_valid_pigeonhole_fm: "¬ (valid (pigeonhole_fm n))"
  unfolding valid_def using interp_of_id_pigeonhole_fm_False[of n]
  by fastforce

lemma cla_imp_I:
  assumes "is_det (eval i a)"
  assumes "is_det (eval i b)"
  assumes "eval i a =   eval i b = "
  shows "eval i (a  b) = "
proof -
  have "is_det tv = (case tv of Det _  True | _  False)" for tv
    by (metis (full_types) tv.exhaust tv.simps(5) tv.simps(6))
  then show ?thesis
    using assms
    by (metis (full_types) eval.simps(4) eval.simps(5) tv.exhaust tv.simps(6))
qed

lemma is_det_NAB: "is_det (eval i ([] ps))"
  unfolding eval_NAB by auto

lemma is_det_ExiEql: "is_det (eval i ([=] ps))"
  using eval_ExiEql by auto

lemma pigeonhole_nat:
  assumes "finite n"
  assumes "finite m"
  assumes "card n > card m"
  assumes "f ` n  m"
  shows "xn. yn. x  y  f x = f y"
  using assms not_le inj_on_iff_card_le unfolding inj_on_def
  by metis

lemma pigeonhole_nat_set:
  assumes "f ` {0..<n}  {0..<m}"
  assumes "m < (n :: nat)"
  shows "j1{0..<n}. j2{0..<n}. j1  j2  f j1 = f j2"
  using assms pigeonhole_nat[of "({0..<n})" "{0..<m}" f]
  by simp

lemma inj_Pro_nat: "(p11) = (p21)  p1 = p2"
  unfolding Pro_nat_def using fm.inject(1) nat_of_string_of_nat
  by metis

lemma eval_true_in_lt_n_pigeonhole_fm:
  assumes "m < n"
  assumes "range i  domain {0..<m}"
  shows "eval i (pigeonhole_fm n) = "
proof -
  {
    assume "eval i ([] ([0..<n]123)) = "
    then have "p  set ([0..<n]123). is_indet (eval i p)"
      using eval_NAB by auto
    then have *: "j<n. is_indet (eval i (j1))"
      unfolding PRO_nat_def by auto
    have **: "j<n. k<m. eval i (j1) = (k)"
    proof -
      have "j<n. is_indet (eval i (j1))  j < n  k<m. eval i (j1) = (k)" for j
      proof (rule_tac x="get_indet (i (string_of_nat j))" in exI)
        show "j<n. is_indet (eval i (j1))  j < n  get_indet (i (string_of_nat j)) < m 
               eval i (j1) = (get_indet (i (string_of_nat j)))"
        proof (induct "i (string_of_nat j)")
          case (Det x)
          then show ?case
            unfolding Pro_nat_def using eval.simps(1) tv.simps(5) by metis
        next
          case (Indet x)
          then show ?case
          proof (subgoal_tac "x<m")
            show "(x) = i (string_of_nat j)  j<n. is_indet (eval i (j1))  j < n 
                   x < m  get_indet (i (string_of_nat j)) < m 
                   eval i (j1) = (get_indet (i (string_of_nat j)))"
              unfolding Pro_nat_def using eval.simps(1) tv.simps(6) by metis
          next
            show "(x) = i (string_of_nat j)  j<n. is_indet (eval i (j1))  j < n  x < m"
              using assms(2) atLeast0LessThan unfolding domain_def by fast
          qed
        qed
      qed
      then show ?thesis
        using * by simp
    qed
    then have "j<n. k<m. get_indet (eval i (j1)) = k"
      by fastforce
    then have "(λj. get_indet (eval i (j1))) ` {0..<n}  {0..<m}"
      by fastforce
    then have "j1  {0..<n}. j2  {0..<n}. j1  j2  get_indet (eval i (j11)) =
                get_indet (eval i (j21))"
      using assms(1) pigeonhole_nat_set by simp
    then have "j1 < n. j2 < n. j1  j2  get_indet (eval i (j11)) =
                get_indet (eval i (j21))"
      using atLeastLessThan_iff by blast
    then have "j1 < n. j2 < n. j1  j2  eval i (j11) = eval i (j21)"
      using ** tv.simps(6) by metis
    then have "(p1, p2)off_diagonal_product (set ([0..<n]123)) (set ([0..<n]123)).
                 eval i p1 = eval i p2"
    proof (rule_tac P="λj1. j1<n  (j2<n. j1  j2  eval i (j11) =
                        eval i (j21))" in exE)
      show "j1<n. j2<n. j1  j2  eval i (j11) = eval i (j21) 
              x<n. j2<n. x  j2  eval i (x1) = eval i (j21)"
        by simp
    next
      show "j1<n. j2<n. j1  j2  eval i (j11) = eval i (j21) 
              j1 < n  (j2<n. j1  j2  eval i (j11) = eval i (j21)) 
              (p1, p2)off_diagonal_product (set ([0..<n]123)) (set ([0..<n]123)).
              eval i p1 = eval i p2" for j1
      proof (rule_tac P="λj2. j2<n  j1  j2  eval i (j11) = eval i (j21)" in exE)
        show "j1<n. j2<n. j1  j2  eval i (j11) = eval i (j21) 
                j1 < n  (j2<n. j1  j2  eval i (j11) = eval i (j21)) 
                x<n. j1  x  eval i (j11) = eval i (x1)"
          by simp
      next
        show "j1<n. j2<n. j1  j2  eval i (j11) = eval i (j21) 
                j1 < n  (j2<n. j1  j2  eval i (j11) = eval i (j21)) 
                j2 < n  j1  j2  eval i (j11) = eval i (j21) 
                (p1, p2)off_diagonal_product (set ([0..<n]123)) (set ([0..<n]123)).
                eval i p1 = eval i p2" for j2
          unfolding off_diagonal_product_def PRO_nat_def using inj_Pro_nat
          by (rule_tac x="(j11, j21)" in bexI) auto
      qed
    qed
    then have "eval i ([=] ([0..<n]123)) = "
      using eval_ExiEql by simp
  }
  then show ?thesis
    unfolding pigeonhole_fm_def using cla_imp_I is_det_ExiEql is_det_NAB by simp
qed

theorem valid_in_lt_n_pigeonhole_fm:
  assumes "m<n"
  shows "valid_in {0..<m} (pigeonhole_fm n)"
  using assms
  unfolding valid_in_def
  using interp_of_id_pigeonhole_fm_False[of n]
  using range_interp_of_id[of n]
  using eval_true_in_lt_n_pigeonhole_fm
  by simp

theorem not_valid_in_pigeonhole_fm_card:
  assumes "finite U"
  shows "¬ valid_in U (pigeonhole_fm (card U))"
  using assms ex_bij_betw_nat_finite not_valid_in_n_pigeonhole_fm bij_betw_valid_in by metis

theorem not_valid_in_pigeonhole_fm_lt_card:
  assumes "finite (U::nat set)"
  assumes "inj_from_to f U W"
  shows "¬ valid_in W (pigeonhole_fm (card U))"
proof -
  have "¬ valid_in U (pigeonhole_fm (card U))"
    using not_valid_in_pigeonhole_fm_card assms by simp
  then show ?thesis
    using assms inj_from_to_valid_in by metis
qed

theorem valid_in_pigeonhole_fm_n_gt_card:
  assumes "finite U"
  assumes "card U < n"
  shows "valid_in U (pigeonhole_fm n)"
  using assms ex_bij_betw_finite_nat bij_betw_valid_in valid_in_lt_n_pigeonhole_fm by metis

section ‹Validity Is the Intersection of the Finite Logics›

lemma "valid p  (U. finite U  valid_in U p)"
proof
  assume "valid p"
  then show "U. finite U  valid_in U p"
    using transfer by blast
next
  assume "U. finite U  valid_in U p"
  then have "valid_in {1..card (props p)} p"
    by simp
  then show "valid p"
    using reduce by simp
qed

section ‹Logics of Different Cardinalities Are Different›

lemma finite_card_lt_valid_in_not_valid_in:
  assumes "finite U"
  assumes "card U < card W"
  shows "valid_in U  valid_in W"
proof -
  have finite_W: "finite W"
    using assms(2) card.infinite by fastforce
  have "valid_in U (pigeonhole_fm (card W))"
    using valid_in_pigeonhole_fm_n_gt_card assms by simp
  moreover
  have "¬ valid_in W (pigeonhole_fm (card W))"
    using not_valid_in_pigeonhole_fm_card assms finite_W by simp
  ultimately show ?thesis
    by fastforce
qed

lemma valid_in_UNIV_p_valid: "valid_in UNIV p = valid p"
  using universal_domain valid_def valid_in_def by simp

theorem infinite_valid_in_valid:
  assumes "infinite U"
  shows "valid_in U p  valid p"
  using assms infinite_valid_in[of U UNIV p] valid_in_UNIV_p_valid by simp

lemma finite_not_finite_valid_in_not_valid_in:
  assumes "finite U  finite W"
  shows "valid_in U  valid_in W"
proof -
  {
    fix U W :: "nat set"
    assume inf: "infinite U"
    assume fin: "finite W"
    then have valid_in_W_pigeonhole_fm: "valid_in W (pigeonhole_fm (Suc (card W)))"
      using valid_in_pigeonhole_fm_n_gt_card[of W] by simp
    have "¬ valid (pigeonhole_fm (Suc (card W)))"
      using not_valid_pigeonhole_fm by simp
    then have "¬ valid_in U (pigeonhole_fm (Suc (card W)))"
      using inf fin infinite_valid_in_valid by simp
    then have "valid_in U  valid_in W"
      using valid_in_W_pigeonhole_fm by fastforce
  }
  then show ?thesis
    using assms by metis
qed

lemma card_not_card_valid_in_not_valid_in:
  assumes "card U  card W"
  shows "valid_in U  valid_in W"
  using assms
proof -
  {
    fix U W :: "nat set"
    assume a: "card U < card W"
    then have "finite W"
      using card.infinite gr_implies_not0 by blast
    then have valid_in_W_pigeonhole_fm: "valid_in W (pigeonhole_fm (Suc (card W)))"
      using valid_in_pigeonhole_fm_n_gt_card[of W] by simp
    have "valid_in U  valid_in W"
    proof (cases "finite U")
      case True
      then show ?thesis
        using a finite_card_lt_valid_in_not_valid_in by simp
    next
      case False
      have "¬ valid (pigeonhole_fm (Suc (card W)))"
        using not_valid_pigeonhole_fm by simp
      then have "¬ valid_in U (pigeonhole_fm (Suc (card W)))"
        using False infinite_valid_in_valid by simp
      then show ?thesis
        using valid_in_W_pigeonhole_fm by fastforce
    qed
  }
  then show ?thesis
    using assms neqE by metis
qed

section ‹Finite Logics Are Different from Infinite Logics›

theorem extend: "valid  valid_in U" if "finite U"
  using that not_valid_pigeonhole_fm valid_in_pigeonhole_fm_n_gt_card by fastforce

corollary "¬ (n. p. valid p  valid_in {0..n} p)"
  using extend by fast

corollary "n. p. ¬ (valid p  valid_in {0..n} p)"
  using extend by fast

corollary "¬ (p. valid p  valid_in {0..n} p)"
  using extend by fast

corollary "valid  valid_in {0..n}"
  using extend by simp

proposition "valid = valid_in {0..}"
  unfolding valid_def valid_in_def
  using universal_domain
  by simp

corollary "valid = valid_in {n..}"
  using infinite_valid_in[of UNIV "{n..}"] universal_domain
  unfolding valid_def valid_in_def
  by (simp add: infinite_Ici)

corollary "¬ (n m. p. valid p  valid_in {m..n} p)"
  using extend by fast

end ― ‹Paraconsistency_Validity_Infinite› file›