Theory HOL-Library.Groups_Big_Fun
section ‹Big sum and product over function bodies›
theory Groups_Big_Fun
imports
  Main
begin
subsection ‹Abstract product›
locale comm_monoid_fun = comm_monoid
begin
definition G :: "('b ⇒ 'a) ⇒ 'a"
where
  expand_set: "G g = comm_monoid_set.F f ❙1 g {a. g a ≠ ❙1}"
interpretation F: comm_monoid_set f "❙1"
  ..
lemma expand_superset:
  assumes "finite A" and "{a. g a ≠ ❙1} ⊆ A"
  shows "G g = F.F g A"
  using F.mono_neutral_right assms expand_set by fastforce
lemma conditionalize:
  assumes "finite A"
  shows "F.F g A = G (λa. if a ∈ A then g a else ❙1)"
  using assms
  by (smt (verit, ccfv_threshold) Diff_iff F.mono_neutral_cong_right expand_set mem_Collect_eq subsetI)
lemma neutral [simp]:
  "G (λa. ❙1) = ❙1"
  by (simp add: expand_set)
lemma update [simp]:
  assumes "finite {a. g a ≠ ❙1}"
  assumes "g a = ❙1"
  shows "G (g(a := b)) = b ❙* G g"
proof (cases "b = ❙1")
  case True with ‹g a = ❙1› show ?thesis
    by (simp add: expand_set) (rule F.cong, auto)
next
  case False
  moreover have "{a'. a' ≠ a ⟶ g a' ≠ ❙1} = insert a {a. g a ≠ ❙1}"
    by auto
  moreover from ‹g a = ❙1› have "a ∉ {a. g a ≠ ❙1}"
    by simp
  moreover have "F.F (λa'. if a' = a then b else g a') {a. g a ≠ ❙1} = F.F g {a. g a ≠ ❙1}"
    by (rule F.cong) (auto simp add: ‹g a = ❙1›)
  ultimately show ?thesis using ‹finite {a. g a ≠ ❙1}› by (simp add: expand_set)
qed
lemma infinite [simp]:
  "¬ finite {a. g a ≠ ❙1} ⟹ G g = ❙1"
  by (simp add: expand_set)
lemma cong [cong]:
  assumes "⋀a. g a = h a"
  shows "G g = G h"
  using assms by (simp add: expand_set)
lemma not_neutral_obtains_not_neutral:
  assumes "G g ≠ ❙1"
  obtains a where "g a ≠ ❙1"
  using assms by (auto elim: F.not_neutral_contains_not_neutral simp add: expand_set)
lemma reindex_cong:
  assumes "bij l"
  assumes "g ∘ l = h"
  shows "G g = G h"
proof -
  from assms have unfold: "h = g ∘ l" by simp
  from ‹bij l› have "inj l" by (rule bij_is_inj)
  then have "inj_on l {a. h a ≠ ❙1}" by (rule subset_inj_on) simp
  moreover from ‹bij l› have "{a. g a ≠ ❙1} = l ` {a. h a ≠ ❙1}"
    by (auto simp add: image_Collect unfold elim: bij_pointE)
  moreover have "⋀x. x ∈ {a. h a ≠ ❙1} ⟹ g (l x) = h x"
    by (simp add: unfold)
  ultimately have "F.F g {a. g a ≠ ❙1} = F.F h {a. h a ≠ ❙1}"
    by (rule F.reindex_cong)
  then show ?thesis by (simp add: expand_set)
qed
lemma distrib:
  assumes "finite {a. g a ≠ ❙1}" and "finite {a. h a ≠ ❙1}"
  shows "G (λa. g a ❙* h a) = G g ❙* G h"
proof -
  from assms have "finite ({a. g a ≠ ❙1} ∪ {a. h a ≠ ❙1})" by simp
  moreover have "{a. g a ❙* h a ≠ ❙1} ⊆ {a. g a ≠ ❙1} ∪ {a. h a ≠ ❙1}"
    by auto (drule sym, simp)
  ultimately show ?thesis
    using assms
    by (simp add: expand_superset [of "{a. g a ≠ ❙1} ∪ {a. h a ≠ ❙1}"] F.distrib)
qed
lemma swap:
  assumes "finite C"
  assumes subset: "{a. ∃b. g a b ≠ ❙1} × {b. ∃a. g a b ≠ ❙1} ⊆ C" (is "?A × ?B ⊆ C")
  shows "G (λa. G (g a)) = G (λb. G (λa. g a b))"
proof -
  from ‹finite C› subset
    have "finite ({a. ∃b. g a b ≠ ❙1} × {b. ∃a. g a b ≠ ❙1})"
    by (rule rev_finite_subset)
  then have fins:
    "finite {b. ∃a. g a b ≠ ❙1}" "finite {a. ∃b. g a b ≠ ❙1}"
    by (auto simp add: finite_cartesian_product_iff)
  have subsets: "⋀a. {b. g a b ≠ ❙1} ⊆ {b. ∃a. g a b ≠ ❙1}"
    "⋀b. {a. g a b ≠ ❙1} ⊆ {a. ∃b. g a b ≠ ❙1}"
    "{a. F.F (g a) {b. ∃a. g a b ≠ ❙1} ≠ ❙1} ⊆ {a. ∃b. g a b ≠ ❙1}"
    "{a. F.F (λaa. g aa a) {a. ∃b. g a b ≠ ❙1} ≠ ❙1} ⊆ {b. ∃a. g a b ≠ ❙1}"
    by (auto elim: F.not_neutral_contains_not_neutral)
  from F.swap have
    "F.F (λa. F.F (g a) {b. ∃a. g a b ≠ ❙1}) {a. ∃b. g a b ≠ ❙1} =
      F.F (λb. F.F (λa. g a b) {a. ∃b. g a b ≠ ❙1}) {b. ∃a. g a b ≠ ❙1}" .
  with subsets fins have "G (λa. F.F (g a) {b. ∃a. g a b ≠ ❙1}) =
    G (λb. F.F (λa. g a b) {a. ∃b. g a b ≠ ❙1})"
    by (auto simp add: expand_superset [of "{b. ∃a. g a b ≠ ❙1}"]
      expand_superset [of "{a. ∃b. g a b ≠ ❙1}"])
  with subsets fins show ?thesis
    by (auto simp add: expand_superset [of "{b. ∃a. g a b ≠ ❙1}"]
      expand_superset [of "{a. ∃b. g a b ≠ ❙1}"])
qed
lemma cartesian_product:
  assumes "finite C"
  assumes subset: "{a. ∃b. g a b ≠ ❙1} × {b. ∃a. g a b ≠ ❙1} ⊆ C" (is "?A × ?B ⊆ C")
  shows "G (λa. G (g a)) = G (λ(a, b). g a b)"
proof -
  from subset ‹finite C› have fin_prod: "finite (?A × ?B)"
    by (rule finite_subset)
  from fin_prod have "finite ?A" and "finite ?B"
    by (auto simp add: finite_cartesian_product_iff)
  have *: "G (λa. G (g a)) =
    (F.F (λa. F.F (g a) {b. ∃a. g a b ≠ ❙1}) {a. ∃b. g a b ≠ ❙1})"
    using ‹finite ?A› ‹finite ?B› expand_superset
    by (smt (verit, del_insts) Collect_mono local.cong not_neutral_obtains_not_neutral)
  have **: "{p. (case p of (a, b) ⇒ g a b) ≠ ❙1} ⊆ ?A × ?B"
    by auto
  show ?thesis
    using ‹finite C› expand_superset
    using "*" ** F.cartesian_product fin_prod by force
qed
lemma cartesian_product2:
  assumes fin: "finite D"
  assumes subset: "{(a, b). ∃c. g a b c ≠ ❙1} × {c. ∃a b. g a b c ≠ ❙1} ⊆ D" (is "?AB × ?C ⊆ D")
  shows "G (λ(a, b). G (g a b)) = G (λ(a, b, c). g a b c)"
proof -
  have bij: "bij (λ(a, b, c). ((a, b), c))"
    by (auto intro!: bijI injI simp add: image_def)
  have "{p. ∃c. g (fst p) (snd p) c ≠ ❙1} × {c. ∃p. g (fst p) (snd p) c ≠ ❙1} ⊆ D"
    by auto (insert subset, blast)
  with fin have "G (λp. G (g (fst p) (snd p))) = G (λ(p, c). g (fst p) (snd p) c)"
    by (rule cartesian_product)
  then have "G (λ(a, b). G (g a b)) = G (λ((a, b), c). g a b c)"
    by (auto simp add: split_def)
  also have "G (λ((a, b), c). g a b c) = G (λ(a, b, c). g a b c)"
    using bij by (rule reindex_cong [of "λ(a, b, c). ((a, b), c)"]) (simp add: fun_eq_iff)
  finally show ?thesis .
qed
lemma delta [simp]:
  "G (λb. if b = a then g b else ❙1) = g a"
proof -
  have "{b. (if b = a then g b else ❙1) ≠ ❙1} ⊆ {a}" by auto
  then show ?thesis by (simp add: expand_superset [of "{a}"])
qed
lemma delta' [simp]:
  "G (λb. if a = b then g b else ❙1) = g a"
proof -
  have "(λb. if a = b then g b else ❙1) = (λb. if b = a then g b else ❙1)"
    by (simp add: fun_eq_iff)
  then have "G (λb. if a = b then g b else ❙1) = G (λb. if b = a then g b else ❙1)"
    by (simp cong del: cong)
  then show ?thesis by simp
qed
end
subsection ‹Concrete sum›
context comm_monoid_add
begin
sublocale Sum_any: comm_monoid_fun plus 0
  rewrites "comm_monoid_set.F plus 0 = sum"
  defines Sum_any = Sum_any.G
proof -
  show "comm_monoid_fun plus 0" ..
  then interpret Sum_any: comm_monoid_fun plus 0 .
  from sum_def show "comm_monoid_set.F plus 0 = sum" by (auto intro: sym)
qed
end
syntax (ASCII)
  "_Sum_any" :: "pttrn ⇒ 'a ⇒ 'a::comm_monoid_add"    (‹(‹indent=3 notation=‹binder SUM››SUM _. _)› [0, 10] 10)
syntax
  "_Sum_any" :: "pttrn ⇒ 'a ⇒ 'a::comm_monoid_add"    (‹(‹indent=2 notation=‹binder ∑››∑_. _)› [0, 10] 10)
syntax_consts
  "_Sum_any" ⇌ Sum_any
translations
  "∑a. b" ⇌ "CONST Sum_any (λa. b)"
lemma Sum_any_left_distrib:
  fixes r :: "'a :: semiring_0"
  assumes "finite {a. g a ≠ 0}"
  shows "Sum_any g * r = (∑n. g n * r)"
  by (metis (mono_tags, lifting) Collect_mono Sum_any.expand_superset assms mult_zero_left sum_distrib_right)
lemma Sum_any_right_distrib:
  fixes r :: "'a :: semiring_0"
  assumes "finite {a. g a ≠ 0}"
  shows "r * Sum_any g = (∑n. r * g n)"
  by (metis (mono_tags, lifting) Collect_mono Sum_any.expand_superset assms mult_zero_right sum_distrib_left)
lemma Sum_any_product:
  fixes f g :: "'b ⇒ 'a::semiring_0"
  assumes "finite {a. f a ≠ 0}" and "finite {b. g b ≠ 0}"
  shows "Sum_any f * Sum_any g = (∑a. ∑b. f a * g b)"
proof -
  have "∀a. (∑b. a * g b) = a * Sum_any g"
    by (simp add: Sum_any_right_distrib assms(2))
  then show ?thesis
    by (simp add: Sum_any_left_distrib assms(1))
qed
lemma Sum_any_eq_zero_iff [simp]: 
  fixes f :: "'a ⇒ nat"
  assumes "finite {a. f a ≠ 0}"
  shows "Sum_any f = 0 ⟷ f = (λ_. 0)"
  using assms by (simp add: Sum_any.expand_set fun_eq_iff)
subsection ‹Concrete product›
context comm_monoid_mult
begin
sublocale Prod_any: comm_monoid_fun times 1
  rewrites "comm_monoid_set.F times 1 = prod"
  defines Prod_any = Prod_any.G
proof -
  show "comm_monoid_fun times 1" ..
  then interpret Prod_any: comm_monoid_fun times 1 .
  from prod_def show "comm_monoid_set.F times 1 = prod" by (auto intro: sym)
qed
end
syntax (ASCII)
  "_Prod_any" :: "pttrn ⇒ 'a ⇒ 'a::comm_monoid_mult"  (‹(‹indent=4 notation=‹binder PROD››PROD _. _)› [0, 10] 10)
syntax
  "_Prod_any" :: "pttrn ⇒ 'a ⇒ 'a::comm_monoid_mult"  (‹(‹indent=2 notation=‹binder ∏››∏_. _)› [0, 10] 10)
syntax_consts
  "_Prod_any" == Prod_any
translations
  "∏a. b" == "CONST Prod_any (λa. b)"
lemma Prod_any_zero:
  fixes f :: "'b ⇒ 'a :: comm_semiring_1"
  assumes "finite {a. f a ≠ 1}"
  assumes "f a = 0"
  shows "(∏a. f a) = 0"
proof -
  from ‹f a = 0› have "f a ≠ 1" by simp
  with ‹f a = 0› have "∃a. f a ≠ 1 ∧ f a = 0" by blast
  with ‹finite {a. f a ≠ 1}› show ?thesis
    by (simp add: Prod_any.expand_set prod_zero)
qed
lemma Prod_any_not_zero:
  fixes f :: "'b ⇒ 'a :: comm_semiring_1"
  assumes "finite {a. f a ≠ 1}"
  assumes "(∏a. f a) ≠ 0"
  shows "f a ≠ 0"
  using assms Prod_any_zero [of f] by blast
lemma power_Sum_any:
  assumes "finite {a. f a ≠ 0}"
  shows "c ^ (∑a. f a) = (∏a. c ^ f a)"
proof -
  have "{a. c ^ f a ≠ 1} ⊆ {a. f a ≠ 0}"
    by (auto intro: ccontr)
  with assms show ?thesis
    by (simp add: Sum_any.expand_set Prod_any.expand_superset power_sum)
qed
end