Theory PiE_Rel_Extras

(* Theory: PiE_Rel_Extras
   Author: Chelsea Edmonds *)

section‹Extensional function extras›
text‹Counting lemmas (i.e. reasoning on cardinality) of sets on the extensional function relation ›

theory PiE_Rel_Extras imports Card_Partitions.Card_Partitions
begin

subsection ‹Relations and Extensional Function sets ›
text ‹A number of lemmas to convert between relations and functions for counting purposes. 
Note, ultimately not needed in this formalisation, but may be of use in the future ›

lemma Range_unfold: "Range r = {y. x. (x, y)  r}"
  by blast

definition fun_to_rel:: " 'a set  'b set   ('a  'b) ('a × 'b) set" where
"fun_to_rel A B f  {(a, b) | a b . a  A  b  B  f a = b}"

definition rel_to_fun:: "('a × 'b) set  ('a  'b)" where
"rel_to_fun R  λ a . (if a  Domain R then (THE b . (a, b)  R) else undefined)"

lemma fun_to_relI: "a  A  b  B  f a = b  (a, b)  fun_to_rel A B f"
  unfolding fun_to_rel_def by auto

lemma fun_to_rel_alt: "fun_to_rel A B f  {(a, f a) | a b . a  A  f a  B}"
  unfolding fun_to_rel_def by simp 

lemma fun_to_relI2: "a  A  f a  B   (a, f a)  fun_to_rel A B f"
  using fun_to_rel_alt by fast

lemma rel_to_fun_in[simp]: "a  Domain R  (rel_to_fun R) a = (THE b . (a, b)  R)"
  unfolding rel_to_fun_def by simp

lemma rel_to_fun_undefined[simp]: "a  Domain R  (rel_to_fun R) a = undefined"
  unfolding rel_to_fun_def by simp

lemma single_valued_unique_Dom_iff: "single_valued R  ( x  Domain R. ∃! y . (x, y)  R)"
  using single_valued_def by fastforce 

lemma rel_to_fun_range:
  assumes "single_valued R"
  assumes "a  Domain R"
  shows "(THE b . (a, b)  R)  Range R"
  using single_valued_unique_Dom_iff
  by (metis Range_iff assms(1) assms(2) theI') 

lemma rel_to_fun_extensional: "single_valued R  rel_to_fun R  (Domain R E Range R)"
  by (intro PiE_I) (simp_all add: rel_to_fun_range)

lemma single_value_fun_to_rel:  "single_valued (fun_to_rel A B f)"
  unfolding single_valued_def fun_to_rel_def
  by simp

lemma fun_to_rel_domain: 
  assumes "f  A E B"
  shows "Domain (fun_to_rel A B f) = A"
  unfolding fun_to_rel_def using assms by (auto simp add: subset_antisym subsetI Domain_unfold)

lemma fun_to_rel_range: 
  assumes "f  A E B"
  shows "Range (fun_to_rel A B f)  B"
  unfolding fun_to_rel_def using assms by (auto simp add: subsetI Range_unfold)

lemma rel_to_fun_to_rel: 
  assumes "f  A E B"
  shows "rel_to_fun (fun_to_rel A B f) = f"
proof (intro ext allI)
  fix x
  show "rel_to_fun (fun_to_rel A B f) x = f x"
  proof (cases "x  A")
    case True
    then have ind: "x  Domain (fun_to_rel A B f)" using fun_to_rel_domain assms 
      by blast
    have "(x, f x)  fun_to_rel A B f" using fun_to_rel_alt True single_value_fun_to_rel
      using assms by fastforce 
    moreover have "rel_to_fun (fun_to_rel A B f) x = (THE b. (x, b)  (fun_to_rel A B f))" by (simp add: ind)
    ultimately show ?thesis using single_value_fun_to_rel single_valuedD the_equality
      by (metis (no_types, lifting)) 
  next
    case False
    then have "x  Domain (fun_to_rel A B f)" unfolding fun_to_rel_def
      by blast 
    then show ?thesis
      using False assms by auto 
  qed
qed

lemma fun_to_rel_to_fun: 
  assumes "single_valued R"
  shows "fun_to_rel (Domain R) (Range R) (rel_to_fun R) = R"
proof (intro subset_antisym subsetI)
  fix x assume "x  fun_to_rel (Domain R) (Range R) (rel_to_fun R)"
  then obtain a b where "x = (a, b)" and "a  Domain R" and "b  Range R" and "(rel_to_fun R a) = b"
    using fun_to_rel_def by (smt (verit) mem_Collect_eq) 
  then have "b = (THE b'. (a, b')  R)" using rel_to_fun_in
    by simp 
  then show "x  R"
    by (metis (no_types, lifting) a  Domain R x = (a, b) assms single_valued_unique_Dom_iff the1_equality)
next
  fix x assume "x  R"
  then obtain a b where "x = (a, b)" and "(a, b)  R" and " c . (a, c)  R  b = c"
    using assms
    by (metis prod.collapse single_valued_def)
  then have "a  Domain R" "b  Range R" by blast+
  then have "b = (THE b' . (a, b')  R)"
    by (metis c. (a, c)  R  b = c x = (a, b) x  R the_equality) 
  then have "(a, b)  fun_to_rel (Domain R) (Range R) (rel_to_fun R)"
    using a  Domain R b  Range R by (intro fun_to_relI) (simp_all)
  then show "x  fun_to_rel (Domain R) (Range R) (rel_to_fun R)" using x = (a, b) by simp
qed

lemma bij_betw_fun_to_rel: 
  assumes "f  A E B"
  shows "bij_betw (λ a . (a, f a)) A (fun_to_rel A B f)"
proof (intro bij_betw_imageI inj_onI)
  show "x y. x  A  y  A  (x, f x) = (y, f y)  x = y" by simp
next
  show "(λa. (a, f a)) ` A = fun_to_rel A B f"
  proof (intro subset_antisym subsetI)
    fix x assume "x  (λa. (a, f a)) ` A"
    then obtain a where "a  A" and "x = (a, f a)" by blast
    then show "x  fun_to_rel A B f" using fun_to_rel_alt assms
      by fastforce 
  next
    fix x assume "x  fun_to_rel A B f"
    then show "x  (λa. (a, f a)) ` A" using fun_to_rel_alt
      using image_iff by fastforce 
  qed
qed

lemma fun_to_rel_indiv_card: 
  assumes "f  A E B"
  shows "card (fun_to_rel A B f) = card A"
  using bij_betw_fun_to_rel assms bij_betw_same_card[of "(λ a . (a, f a))" A "(fun_to_rel A B f)"]
  by (metis)

lemma fun_to_rel_inj: 
  assumes "C  A E B"
  shows "inj_on (fun_to_rel A B) C"
proof (intro inj_onI ext allI)
  fix f g x  assume fin: "f  C" and gin: "g  C" and eq: "fun_to_rel A B f = fun_to_rel A B g"
  then show "f x = g x"
  proof (cases "x  A")
    case True
    then have "(x, f x)  fun_to_rel A B f" using fun_to_rel_alt
      by (smt (verit) PiE_mem assms fin fun_to_rel_def mem_Collect_eq subset_eq)
    moreover have "(x, g x)  fun_to_rel A B g" using fun_to_rel_alt True
      by (smt (verit) PiE_mem assms fun_to_rel_def gin mem_Collect_eq subset_eq)
    ultimately show ?thesis  using eq single_value_fun_to_rel single_valued_def
      by metis 
  next
    case False
    then have "f x = undefined" "g x = undefined" using fin gin assms by auto 
    then show ?thesis by simp
  qed
qed

lemma fun_to_rel_ss: "fun_to_rel A B f  A × B"
  unfolding fun_to_rel_def by auto

lemma card_fun_to_rel: "C  A E B  card C = card ((λ f . fun_to_rel A B f ) ` C)"
  using card_image fun_to_rel_inj by metis 

subsection ‹Cardinality Lemmas ›
text ‹Lemmas to count variations of filtered sets over the extensional function set relation ›

lemma card_PiE_filter_range_set:
  assumes " a. a  A'  X a  C"
  assumes "A'  A"
  assumes "finite A"
  shows "card {f  A E C .  a  A' . f a = X a} = (card C)^(card A - card A')"
proof -
  have finA: "finite A'" using assms(3) finite_subset assms(2) by auto 
  have c1: "card (A - A') = card A - card A'" using assms(2)
  using card_Diff_subset finA by blast 
  define g :: "('a   'b)  ('a   'b)" where "g  λ f. (λ a' . if a'  A' then undefined else f a')"
  have "bij_betw g {f  A E C .  a  A' . f a = X a} ((A - A') E C)"
  proof (intro bij_betw_imageI inj_onI)
    fix h h' assume h1in: "h  {f  A E C.  a  A' . f a = X a}" and h2in: "h'  {f  A E C.  a  A' . f a = X a}" "g h = g h'"
    then have eq: "(λ a' . if a'  A' then undefined  else h a') = (λ a' .  if a'  A' then undefined else h' a')"
      using g_def by simp
    show "h = h'"
    proof (intro ext allI)
      fix x
      show "h x = h' x" using h1in h2in eq by (cases "x  A'", simp, meson)
    qed
  next
    show "g ` {f  A E C.  a  A' . f a = X a} = A - A' E C"
    proof (intro subset_antisym subsetI)
      fix g' assume "g'  g ` {f  A E C.  a  A' . f a = X a}"
      then obtain f' where geq: "g' = g f'" and fin: "f'  A E C" and " a  A' . f' a = X a"
        by blast
      show "g'  A - A' E C"
        using g_def fin geq by (intro PiE_I)(auto)
    next
      fix g' assume gin: "g'  A - A' E C"
      define f' where "f' = (λ a' . (if a'  A' then X a' else g' a'))" 
      then have eqc: " a'  A' . f' a' = X a'" by auto
      have fin: "f'  A E C"
      proof (intro PiE_I)
        fix x assume "x  A"
        have "x  A'  f' x = g' x" using f'_def by auto
        moreover have "x  A'  f' x = X x" using f'_def by (simp add: x  A) 
        ultimately show "f' x  C"
          using gin  PiE_E x  A assms(1)[of x] by (metis Diff_iff) 
      next
        fix x assume "x  A"
        then show "f' x = undefined"
          using f'_def gin assms(2) by auto 
      qed
      have "g' = g f'" unfolding f'_def g_def 
        by (auto simp add: fun_eq_iff) (metis DiffE PiE_arb gin) 
      then show "g'  g ` {f  A E C.  a  A' . f a = X a}" using fin eqc by blast
    qed
  qed
  then have "card {f  A E C .  a  A' . f a = X a} = card ((A - A') E C)"
    using bij_betw_same_card by blast
  also have "... = (card C)^card (A - A')" 
    using card_funcsetE assms(3) by (metis finite_Diff) 
  finally show ?thesis using c1 by auto
qed

lemma card_PiE_filter_range_indiv: "X a'  C  a'  A  finite A 
    card {f  A E C . f a' = X a'} = (card C)^(card A - 1)"
  using card_PiE_filter_range_set[of "{a'}" X C A ] by auto

lemma card_PiE_filter_range_set_const: "c  C  A'  A  finite A  
    card {f  A E C .  a  A' . f a = c} = (card C)^(card A - card A')"
  using card_PiE_filter_range_set[of A' "λ a . c"] by auto

lemma card_PiE_filter_range_set_nat: "c  {0..<n}  A'  A  finite A 
    card {f  A E {0..<n} .  a  A' . f a = c} = n^(card A - card A')"
  using card_PiE_filter_range_set_const[of c "{0..<n}" A' A] by auto

end