Theory Banach_Tarski_Theorem

(*  Title:       Banach_Tarski_Theorem.thy
    Author:      Arthur F. Ramos, David Barros Hulak, Ruy J. G. B. de Queiroz, 2026

    The main theorem.

    Statement (Banach-Tarski, modern form):
      The closed unit ball B^3 in R^3 admits a finite partition into pieces
      that can be reassembled, by isometries of R^3, into TWO disjoint copies
      of B^3.
*)

theory Banach_Tarski_Theorem
  imports Ball_Decomposition
begin

text ‹
  Two copies of the ball, embedded in disjoint regions of ‹ℝ3›.
›

definition shift3 :: "real^3" where
  "shift3 = vector [3, 0, 0]"

definition ball3_copy_left :: "(real^3) set" where
  "ball3_copy_left = ball3"  (* the ball in the original location *)

definition ball3_copy_right :: "(real^3) set" where
  "ball3_copy_right = (+) shift3 ` ball3"  (* shifted by 3e_1 *)

lemma norm_shift3 [simp]: "norm shift3 = 3"
  unfolding shift3_def
  by (simp add: norm_eq_sqrt_inner inner_vec_def sum_3)

lemma ball3_copies_disjoint:
  "ball3_copy_left ∩ ball3_copy_right = {}"
proof
  show "ball3_copy_left ∩ ball3_copy_right ⊆ {}"
  proof
    fix z
    assume "z ∈ ball3_copy_left ∩ ball3_copy_right"
    then obtain y where z_ball: "z ∈ ball3" and y_ball: "y ∈ ball3" and z_eq: "z = shift3 + y"
      unfolding ball3_copy_left_def ball3_copy_right_def by auto
    have z_norm: "norm z ≤ 1" and y_norm: "norm y ≤ 1"
      using z_ball y_ball by (simp_all add: ball3_def)
    have tri: "norm (z - y) ≤ norm z + norm y"
      using norm_triangle_ineq4 by blast
    have "3 = norm (z - y)"
      using z_eq by simp
    also have "… ≤ norm z + norm y"
      by (rule tri)
    also have "… ≤ 2"
      using z_norm y_norm by simp
    finally show "z ∈ {}"
      by simp
  qed
qed simp

text ‹
  Isometries of ‹ℝ3› are the motions used in the final assembly.
  Rotations from ‹SO(3)›, translations, and their compositions are
  isometries.
›

definition isometry :: "(real^3 ⇒ real^3) ⇒ bool" where
  "isometry f ⟷ (∀x y. dist (f x) (f y) = dist x y)"

lemma id_isometry [simp]: "isometry id"
  by (simp add: isometry_def)

lemma translation_isometry [simp]: "isometry ((+) a)"
  by (simp add: isometry_def dist_norm)

lemma SO3_isometry:
  assumes "g ∈ SO3"
  shows "isometry g"
  using assms
  by (auto simp add: SO3_def rotation_def isometry_def orthogonal_transformation_isometry)

lemma isometry_compose:
  assumes "isometry f" "isometry g"
  shows "isometry (f ∘ g)"
  using assms by (simp add: isometry_def)

lemma translation_compose_SO3_isometry [simp]:
  assumes "g ∈ SO3"
  shows "isometry ((+) a ∘ g)"
  using assms by (intro isometry_compose translation_isometry SO3_isometry)

lemma offcenter_rotation_isometry:
  assumes "R ∈ SO3"
  shows "isometry (λx. c + R (x - c))"
proof -
  have "(λx. c + R (x - c)) = (+) c ∘ R ∘ (+) (- c)"
    by (rule ext) simp
  thus ?thesis
    using assms by (simp add: isometry_compose SO3_isometry)
qed

lemma offcenter_rotation_inverse_left:
  fixes c :: "real^3"
  assumes inv_left: "Rinv ∘ R = id"
  defines "T ≡ λx. c + R (x - c)"
    and "U ≡ λx. c + Rinv (x - c)"
  shows "U (T x) = x"
  using fun_cong[OF inv_left, of "x - c"]
  by (simp add: T_def U_def)

lemma offcenter_rotation_inverse_right:
  fixes c :: "real^3"
  assumes inv_right: "R ∘ Rinv = id"
  defines "T ≡ λx. c + R (x - c)"
    and "U ≡ λx. c + Rinv (x - c)"
  shows "T (U x) = x"
  using fun_cong[OF inv_right, of "x - c"]
  by (simp add: T_def U_def)

lemma offcenter_rotation_funpow_zero:
  fixes c :: "real^3" and R :: "real^3 ⇒ real^3"
  defines "T ≡ λx. c + R (x - c)"
  shows "(T ^^ n) 0 = c + (R ^^ n) (- c)"
proof (induction n)
  case 0
  show ?case
    by simp
next
  case (Suc n)
  have "(T ^^ Suc n) 0 = T ((T ^^ n) 0)"
    by simp
  also have "… = T (c + (R ^^ n) (- c))"
    using Suc.IH by simp
  also have "… = c + R ((R ^^ n) (- c))"
    by (simp add: T_def)
  also have "… = c + (R ^^ Suc n) (- c)"
    by simp
  finally show ?case .
qed

lemma sigma_replicate_b:
  "sigma (replicate n (False, B)) = (Rz ^^ n)"
  by (induction n) (simp_all add: letter_to_rot_def)

lemma canceled_replicate_b: "canceled (replicate n (False, B))"
  unfolding canceled_def
proof
  assume "Domainp cancels_to_1 (replicate n (False, B))"
  then obtain w where "cancels_to_1 (replicate n (False, B)) w"
    by auto
  then obtain i where i: "Suc i < length (replicate n (False, B))"
    and "canceling (replicate n (False, B) ! i) (replicate n (False, B) ! Suc i)"
    by (auto simp: cancels_to_1_def cancels_to_1_at_def)
  hence "canceling (False, B) (False, B)"
    by simp
  thus False
    by (simp add: canceling_def)
qed

lemma replicate_b_in_F2: "replicate n (False, B) ∈ carrier F2"
  by (intro canceled_in_F2 canceled_replicate_b)

theorem ball3_paradoxical_strong:
  "∃P Q :: (real^3) set list. ∃gP gQ :: ((real^3) ⇒ (real^3)) list.
       length P = length gP ∧ length Q = length gQ ∧
       (∀g ∈ set gP. isometry g) ∧ (∀g ∈ set gQ. isometry g) ∧
       pairwise_disjoint (P @ Q) ∧
       pairwise_disjoint (map2 (λg A. g ` A) gP P) ∧
       pairwise_disjoint (map2 (λg A. g ` A) gQ Q) ∧
       (∀i < length P. P ! i ⊆ ball3) ∧
       (∀i < length Q. Q ! i ⊆ ball3) ∧
       ball3 = (⋃i<length P. P ! i) ∪ (⋃i<length Q. Q ! i) ∧
       ball3 = (⋃i<length P. (gP ! i) ` (P ! i)) ∧
       ball3 = (⋃i<length Q. (gQ ! i) ` (Q ! i))"
proof -
  obtain a where a_sphere: "a ∈ sphere2" and a_not_D: "a ∉ bad_set_D"
    using exists_antipodal_axis_avoiding_countable[OF bad_set_D_countable] by blast
  let ?c = "- (1 / 2) *R a"
  define T where "T = (λx. ?c + Rz (x - ?c))"
  define U where "U = (λx. ?c + Rz_inv (x - ?c))"
  have T_iso: "isometry T"
    unfolding T_def by (rule offcenter_rotation_isometry[OF Rz_in_SO3])
  have U_iso: "isometry U"
    unfolding U_def by (rule offcenter_rotation_isometry[OF Rz_inv_in_SO3])
  have U_T: "⋀x. U (T x) = x"
    unfolding T_def U_def
    by (rule offcenter_rotation_inverse_left[OF Rz_inv_left])
  have T_U: "⋀x. T (U x) = x"
    unfolding T_def U_def
    by (rule offcenter_rotation_inverse_right[OF Rz_inv_right])

  have no_Rz_power_fix: "⋀n. n > 0 ⟹ (Rz ^^ n) a ≠ a"
  proof
    fix n :: nat
    assume n_pos: "n > 0" and fixed: "(Rz ^^ n) a = a"
    let ?w = "replicate n (False, B)"
    have w_carrier: "?w ∈ carrier F2"
      by (rule replicate_b_in_F2)
    have w_ne: "?w ≠ []"
      using n_pos by auto
    have "sigma ?w a = a"
      using fixed by (simp add: sigma_replicate_b)
    hence "a ∈ fixed_point_set (sigma ?w)"
      using a_sphere by (simp add: fixed_point_set_def)
    hence "a ∈ bad_set_D"
      unfolding bad_set_D_def using w_carrier w_ne by blast
    with a_not_D show False
      by contradiction
  qed

  have Rz_power_a_inj: "⋀n m. (Rz ^^ n) a = (Rz ^^ m) a ⟹ n = m"
  proof -
    fix n m :: nat
    assume eq: "(Rz ^^ n) a = (Rz ^^ m) a"
    show "n = m"
    proof (cases n m rule: linorder_cases)
      case less
      let ?d = "m - n"
      have d_pos: "?d > 0"
        using less by simp
      have m_eq: "m = n + ?d"
        using less by simp
      have "(Rz ^^ n) a = (Rz ^^ n) ((Rz ^^ ?d) a)"
        using eq m_eq by (metis comp_apply funpow_add)
      hence "a = (Rz ^^ ?d) a"
        using SO3_inj[OF SO3_funpow[OF Rz_in_SO3, of n]] by (auto simp: inj_def)
      with no_Rz_power_fix[OF d_pos] show ?thesis
        by simp
    next
      case equal
      then show ?thesis .
    next
      case greater
      let ?d = "n - m"
      have d_pos: "?d > 0"
        using greater by simp
      have n_eq: "n = m + ?d"
        using greater by simp
      have "(Rz ^^ m) a = (Rz ^^ m) ((Rz ^^ ?d) a)"
        using eq n_eq by (metis comp_apply funpow_add)
      hence "a = (Rz ^^ ?d) a"
        using SO3_inj[OF SO3_funpow[OF Rz_in_SO3, of m]] by (auto simp: inj_def)
      with no_Rz_power_fix[OF d_pos] show ?thesis
        by simp
    qed
  qed

  have T_pow_zero: "⋀n. (T ^^ n) 0 = ?c + (Rz ^^ n) (- ?c)"
    unfolding T_def by (rule offcenter_rotation_funpow_zero)
  have T_pow_zero_diff: "⋀n. (T ^^ n) 0 = (1 / 2) *R ((Rz ^^ n) a - a)"
  proof -
    fix n
    have lin: "linear (Rz ^^ n)"
      by (rule SO3_linear[OF SO3_funpow[OF Rz_in_SO3]])
    have "(T ^^ n) 0 = ?c + (Rz ^^ n) (- ?c)"
      by (rule T_pow_zero)
    also have "… = (- (1 / 2) *R a) + (1 / 2) *R ((Rz ^^ n) a)"
      using linear_scale[OF lin, of "1 / 2" a] by simp
    also have "… = (1 / 2) *R ((Rz ^^ n) a - a)"
      by (simp add: scaleR_right_diff_distrib)
    finally show "(T ^^ n) 0 = (1 / 2) *R ((Rz ^^ n) a - a)" .
  qed

  have T_orbit_inj: "⋀n m. (T ^^ n) 0 = (T ^^ m) 0 ⟹ n = m"
  proof -
    fix n m :: nat
    assume eq: "(T ^^ n) 0 = (T ^^ m) 0"
    have "(Rz ^^ n) a = (Rz ^^ m) a"
      using eq T_pow_zero_diff by simp
    thus "n = m"
      by (rule Rz_power_a_inj)
  qed
  have orbit_disj:
    "∀n m. n ≠ m ⟶ ((T^^n) ` {0}) ∩ ((T^^m) ` {0}) = {}"
    using T_orbit_inj by auto

  define E where "E = (⋃n. (T^^n) ` {0::real^3})"
  have T_E: "T ` E = E - {0}"
    unfolding E_def by (rule absorbing_rotation_shift[OF orbit_disj])
  have zero_subset_E: "{0::real^3} ⊆ E"
  proof
    fix x :: "real^3"
    assume "x ∈ {0}"
    hence "x ∈ (T ^^ 0) ` {0}"
      by simp
    thus "x ∈ E"
      unfolding E_def by blast
  qed
  have E_subset_ball3: "E ⊆ ball3"
  proof
    fix x
    assume "x ∈ E"
    then obtain n where x_eq: "x = (T ^^ n) 0"
      unfolding E_def by blast
    have Rza_sphere: "(Rz ^^ n) a ∈ sphere2"
      using SO3_funpow_preserves_sphere2[OF Rz_in_SO3 a_sphere] .
    have "norm x = norm ((1 / 2) *R ((Rz ^^ n) a - a))"
      using x_eq T_pow_zero_diff by simp
    also have "… = (1 / 2) * norm ((Rz ^^ n) a - a)"
      by simp
    also have "… ≤ (1 / 2) * (norm ((Rz ^^ n) a) + norm a)"
      by (intro mult_left_mono norm_triangle_ineq4) simp
    also have "… = 1"
      using Rza_sphere a_sphere by (simp add: sphere2_def)
    finally show "x ∈ ball3"
      by (simp add: ball3_def)
  qed

  let ?X = "ball3 - {0::real^3}"
  let ?Y = "ball3"
  let ?A = "[E, ball3 - E]"
  let ?B = "[T ` E, ball3 - E]"
  let ?e = "[T, id]"
  let ?t = "[U, id]"
  have A_cover: "?Y = (⋃k<length ?A. ?A ! k)"
    using E_subset_ball3 by (auto simp: lessThan_Suc)
  have A_disj: "pairwise_disjoint ?A"
    unfolding pairwise_disjoint_def
  proof (intro allI impI)
    fix i j
    assume i: "i < length ?A" and j: "j < length ?A" and ij: "i ≠ j"
    have "(i = 0 ∧ j = 1) ∨ (i = 1 ∧ j = 0)"
      using i j ij by auto
    thus "?A ! i ∩ ?A ! j = {}"
      by auto
  qed
  have B_cover: "?X = (⋃k<length ?B. ?B ! k)"
  proof
    show "?X ⊆ (⋃k<length ?B. ?B ! k)"
    proof
      fix x
      assume x: "x ∈ ?X"
      show "x ∈ (⋃k<length ?B. ?B ! k)"
      proof (cases "x ∈ E")
        case True
        with x T_E show ?thesis
          by force
      next
        case False
        with x show ?thesis
          by force
      qed
    qed
    show "(⋃k<length ?B. ?B ! k) ⊆ ?X"
    proof
      fix x
      assume x: "x ∈ (⋃k<length ?B. ?B ! k)"
      then obtain k where k: "k < length ?B" and xk: "x ∈ ?B ! k"
        by blast
      have "k = 0 ∨ k = 1"
        using k by auto
      thus "x ∈ ?X"
      proof
        assume "k = 0"
        with xk T_E E_subset_ball3 show ?thesis
          by auto
      next
        assume "k = 1"
        with xk zero_subset_E show ?thesis
          by auto
      qed
    qed
  qed
  have B_disj: "pairwise_disjoint ?B"
    unfolding pairwise_disjoint_def
  proof (intro allI impI)
    fix i j
    assume i: "i < length ?B" and j: "j < length ?B" and ij: "i ≠ j"
    have "(i = 0 ∧ j = 1) ∨ (i = 1 ∧ j = 0)"
      using i j ij by auto
    thus "?B ! i ∩ ?B ! j = {}"
      using T_E by auto
  qed
  have e_left: "⋀k x. ⟦k < length ?A; x ∈ ?A ! k⟧
      ⟹ (?e ! k) x ∈ ?B ! k ∧ (?t ! k) ((?e ! k) x) = x"
  proof -
    fix k x
    assume k: "k < length ?A" and x: "x ∈ ?A ! k"
    have "k = 0 ∨ k = 1"
      using k by auto
    thus "(?e ! k) x ∈ ?B ! k ∧ (?t ! k) ((?e ! k) x) = x"
    proof
      assume "k = 0"
      with x U_T show ?thesis
        by auto
    next
      assume "k = 1"
      with x show ?thesis
        by auto
    qed
  qed
  have t_left: "⋀k y. ⟦k < length ?B; y ∈ ?B ! k⟧
      ⟹ (?t ! k) y ∈ ?A ! k ∧ (?e ! k) ((?t ! k) y) = y"
  proof -
    fix k y
    assume k: "k < length ?B" and y: "y ∈ ?B ! k"
    have "k = 0 ∨ k = 1"
      using k by auto
    thus "(?t ! k) y ∈ ?A ! k ∧ (?e ! k) ((?t ! k) y) = y"
    proof
      assume "k = 0"
      then obtain x where x: "x ∈ E" and y_eq: "y = T x"
        using y by auto
      hence "U y = x"
        using U_T by simp
      with x y_eq T_U ‹k = 0› show ?thesis
        by simp
    next
      assume "k = 1"
      with y show ?thesis
        by auto
    qed
  qed

  from ball3_minus_origin_paradoxical_strong obtain P Q :: "(real^3) set list"
    and gP gQ :: "((real^3) ⇒ (real^3)) list"
    where lenP: "length P = length gP"
      and lenQ: "length Q = length gQ"
      and gP_SO3: "set gP ⊆ SO3"
      and gQ_SO3: "set gQ ⊆ SO3"
      and source_disj: "pairwise_disjoint (P @ Q)"
      and imageP_disj: "pairwise_disjoint (map2 (λg A. g ` A) gP P)"
      and imageQ_disj: "pairwise_disjoint (map2 (λg A. g ` A) gQ Q)"
      and P_sub: "∀i < length P. P ! i ⊆ ?X"
      and Q_sub: "∀i < length Q. Q ! i ⊆ ?X"
      and source_cover: "?X = (⋃i<length P. P ! i) ∪ (⋃i<length Q. Q ! i)"
      and imageP_cover: "?X = (⋃i<length P. (gP ! i) ` (P ! i))"
      and imageQ_cover: "?X = (⋃i<length Q. (gQ ! i) ` (Q ! i))"
    by auto
  have gP_inj: "⋀i. i < length P ⟹ inj (gP ! i)"
    using SO3_inj gP_SO3 lenP nth_mem by auto
  have gQ_inj: "⋀i. i < length Q ⟹ inj (gQ ! i)"
    using SO3_inj gQ_SO3 lenQ nth_mem by auto
  have mapsP: "⋀k i l. ⟦k < length ?A; i < length P; l < length ?B⟧
      ⟹ transfer_map ?t gP ?e k i l ∈ {f. isometry f}"
  proof -
    fix k i l
    assume k: "k < length ?A" and i: "i < length P" and l: "l < length ?B"
    have gi_SO3: "gP ! i ∈ SO3"
      using gP_SO3 i lenP by auto
    have gi_iso: "isometry (gP ! i)"
      by (rule SO3_isometry[OF gi_SO3])
    have ek_iso: "isometry (?e ! k)"
      using T_iso k less_Suc_eq by fastforce
    have tl_iso: "isometry (?t ! l)"
      using U_iso l less_Suc_eq by fastforce
    show "transfer_map ?t gP ?e k i l ∈ {f. isometry f}"
      unfolding transfer_map_def
      by (simp add: isometry_compose tl_iso gi_iso ek_iso)
  qed
  have mapsQ: "⋀k i l. ⟦k < length ?A; i < length Q; l < length ?B⟧
      ⟹ transfer_map ?t gQ ?e k i l ∈ {f. isometry f}"
  proof -
    fix k i l
    assume k: "k < length ?A" and i: "i < length Q" and l: "l < length ?B"
    have gi_SO3: "gQ ! i ∈ SO3"
      using gQ_SO3 i lenQ by auto
    have gi_iso: "isometry (gQ ! i)"
      by (rule SO3_isometry[OF gi_SO3])
    have ek_iso: "isometry (?e ! k)"
      using T_iso k less_Suc_eq by fastforce
    have tl_iso: "isometry (?t ! l)"
      using U_iso l less_Suc_eq by fastforce
    show "transfer_map ?t gQ ?e k i l ∈ {f. isometry f}"
      unfolding transfer_map_def
      by (simp add: isometry_compose tl_iso gi_iso ek_iso)
  qed
  have lenAB: "length ?A = length ?B"
    by simp
  from transfer_partitioned_paradox[
      OF lenAB A_cover A_disj B_cover B_disj e_left t_left lenP lenQ source_disj
        source_cover imageP_disj imageQ_disj imageP_cover imageQ_cover gP_inj gQ_inj
        mapsP mapsQ]
  obtain P' Q' :: "(real^3) set list" and hP hQ :: "((real^3) ⇒ (real^3)) list"
    where lenP': "length P' = length hP"
      and lenQ': "length Q' = length hQ"
      and hP_iso: "set hP ⊆ {f. isometry f}"
      and hQ_iso: "set hQ ⊆ {f. isometry f}"
      and source_disj': "pairwise_disjoint (P' @ Q')"
      and imageP_disj': "pairwise_disjoint (map2 (λg A. g ` A) hP P')"
      and imageQ_disj': "pairwise_disjoint (map2 (λg A. g ` A) hQ Q')"
      and source_cover': "?Y = (⋃i<length P'. P' ! i) ∪ (⋃i<length Q'. Q' ! i)"
      and imageP_cover': "?Y = (⋃i<length P'. (hP ! i) ` (P' ! i))"
      and imageQ_cover': "?Y = (⋃i<length Q'. (hQ ! i) ` (Q' ! i))"
    by auto
  have P'_sub: "∀i < length P'. P' ! i ⊆ ball3"
    using source_cover' by blast
  have Q'_sub: "∀i < length Q'. Q' ! i ⊆ ball3"
    using source_cover' by blast
  show ?thesis
  proof (intro exI conjI)
    show "length P' = length hP"
      by (rule lenP')
    show "length Q' = length hQ"
      by (rule lenQ')
    show "∀g∈set hP. isometry g"
      using hP_iso by blast
    show "∀g∈set hQ. isometry g"
      using hQ_iso by blast
    show "pairwise_disjoint (P' @ Q')"
      by (rule source_disj')
    show "pairwise_disjoint (map2 (λg A. g ` A) hP P')"
      by (rule imageP_disj')
    show "pairwise_disjoint (map2 (λg A. g ` A) hQ Q')"
      by (rule imageQ_disj')
    show "∀i<length P'. P' ! i ⊆ ball3"
      by (rule P'_sub)
    show "∀i<length Q'. Q' ! i ⊆ ball3"
      by (rule Q'_sub)
    show "ball3 = (⋃i<length P'. P' ! i) ∪ (⋃i<length Q'. Q' ! i)"
      by (rule source_cover')
    show "ball3 = (⋃i<length P'. (hP ! i) ` (P' ! i))"
      by (rule imageP_cover')
    show "ball3 = (⋃i<length Q'. (hQ ! i) ` (Q' ! i))"
      by (rule imageQ_cover')
  qed
qed

text ‹An auxiliary finite-cover theorem for the closed unit ball.›
theorem banach_tarski_finite_cover:
  "∃P :: (real^3) set list. ∃gs :: ((real^3) ⇒ (real^3)) list.
       length P = length gs ∧
       (∀g ∈ set gs. isometry g) ∧
       (∀i < length P. P ! i ⊆ ball3) ∧
       ball3 = (⋃i<length P. P ! i) ∧
       (ball3_copy_left ∪ ball3_copy_right) =
         (⋃i<length P. (gs ! i) ` (P ! i)) ∧
       ball3_copy_left ∩ ball3_copy_right = {}"
proof -
  from ball3_paradoxical obtain P Q :: "(real^3) set list"
    and gP gQ :: "((real^3 ⇒ real^3)) list"
    where decomp:
      "length P = length gP ∧ length Q = length gQ ∧
       set gP ⊆ SO3 ∧ set gQ ⊆ SO3 ∧
       (∀i < length P. P ! i ⊆ ball3) ∧
       (∀i < length Q. Q ! i ⊆ ball3) ∧
       ball3 = (⋃i<length P. P ! i) ∧
       ball3 = (⋃i<length Q. Q ! i) ∧
       ball3 = (⋃i<length P. (gP ! i) ` (P ! i)) ∧
       ball3 = (⋃i<length Q. (gQ ! i) ` (Q ! i))"
    by (elim exE)
  from decomp have lenP: "length P = length gP"
    by (elim conjE)
  from decomp have lenQ: "length Q = length gQ"
    by (elim conjE)
  from decomp have gP_SO3: "set gP ⊆ SO3"
    by (elim conjE)
  from decomp have gQ_SO3: "set gQ ⊆ SO3"
    by (elim conjE)
  from decomp have P_sub: "∀i < length P. P ! i ⊆ ball3"
    by (elim conjE)
  from decomp have Q_sub: "∀i < length Q. Q ! i ⊆ ball3"
    by (elim conjE)
  from decomp have P_src: "ball3 = (⋃i<length P. P ! i)"
    by (elim conjE)
  from decomp have Q_src: "ball3 = (⋃i<length Q. Q ! i)"
    by (elim conjE)
  from decomp have P_cov: "ball3 = (⋃i<length P. (gP ! i) ` (P ! i))"
    by (elim conjE)
  from decomp have Q_cov: "ball3 = (⋃i<length Q. (gQ ! i) ` (Q ! i))"
    by (elim conjE)

  define pieces where "pieces = P @ Q"
  define hQ where "hQ = map (λg. (+) shift3 ∘ g) gQ"
  define gs where "gs = gP @ hQ"
  have len_hQ: "length Q = length hQ"
    by (simp add: hQ_def lenQ)
  have len: "length pieces = length gs"
    by (simp add: pieces_def gs_def lenP len_hQ)
  have iso: "∀g ∈ set gs. isometry g"
    using gP_SO3 gQ_SO3
    by (auto simp add: gs_def hQ_def SO3_isometry)
  have sub: "∀i < length pieces. pieces ! i ⊆ ball3"
    using P_sub Q_sub by (auto simp add: pieces_def nth_append)
  have src: "ball3 = (⋃i<length pieces. pieces ! i)"
  proof -
    have append_union:
      "(⋃i<length (P @ Q). (P @ Q) ! i) =
        (⋃i<length P. P ! i) ∪ (⋃i<length Q. Q ! i)"
      using indexed_union_append[of P Q] .
    have "(⋃i<length pieces. pieces ! i) =
        (⋃i<length P. P ! i) ∪ (⋃i<length Q. Q ! i)"
      unfolding pieces_def
      using append_union .
    also have "… = ball3"
      using P_src Q_src by simp
    finally show ?thesis by simp
  qed
  have right_cov:
    "ball3_copy_right = (⋃i<length Q. (hQ ! i) ` (Q ! i))"
  proof -
    have right_union:
      "(⋃i<length Q. (hQ ! i) ` (Q ! i)) =
        (+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i))"
    proof (rule equalityI)
      show "(⋃i<length Q. (hQ ! i) ` (Q ! i)) ⊆
          (+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i))"
      proof
        fix x assume "x ∈ (⋃i<length Q. (hQ ! i) ` (Q ! i))"
        then obtain i y where i_lt: "i < length Q" and y_in: "y ∈ Q ! i"
          and x_eq: "x = (hQ ! i) y"
          by blast
        have h_eq: "hQ ! i = (+) shift3 ∘ (gQ ! i)"
          using i_lt lenQ by (simp add: hQ_def)
        have "(gQ ! i) y ∈ (⋃i<length Q. (gQ ! i) ` (Q ! i))"
          using i_lt y_in by blast
        moreover have "x = shift3 + (gQ ! i) y"
          using x_eq h_eq by simp
        ultimately show "x ∈ (+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i))"
          by blast
      qed
      show "(+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i)) ⊆
          (⋃i<length Q. (hQ ! i) ` (Q ! i))"
      proof
        fix x assume "x ∈ (+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i))"
        then obtain z i y where x_eq: "x = shift3 + z"
          and i_lt: "i < length Q" and y_in: "y ∈ Q ! i" and z_eq: "z = (gQ ! i) y"
          by blast
        have h_eq: "hQ ! i = (+) shift3 ∘ (gQ ! i)"
          using i_lt lenQ by (simp add: hQ_def)
        have "x = (hQ ! i) y"
          using x_eq z_eq h_eq by simp
        thus "x ∈ (⋃i<length Q. (hQ ! i) ` (Q ! i))"
          using i_lt y_in by blast
      qed
    qed
    show ?thesis
      unfolding ball3_copy_right_def
      using right_union Q_cov by simp
  qed
  have images:
    "ball3_copy_left ∪ ball3_copy_right =
      (⋃i<length pieces. (gs ! i) ` (pieces ! i))"
  proof -
    have append_images:
      "(⋃i<length (P @ Q). (gP @ hQ) ! i ` ((P @ Q) ! i)) =
        (⋃i<length P. (gP ! i) ` (P ! i)) ∪
        (⋃i<length Q. (hQ ! i) ` (Q ! i))"
      using indexed_image_union_append[OF lenP len_hQ] .
    have "(⋃i<length pieces. (gs ! i) ` (pieces ! i)) =
        (⋃i<length P. (gP ! i) ` (P ! i)) ∪
        (⋃i<length Q. (hQ ! i) ` (Q ! i))"
      unfolding pieces_def gs_def
      using append_images .
    also have "… = ball3_copy_left ∪ ball3_copy_right"
      using P_cov right_cov by (simp add: ball3_copy_left_def)
    finally show ?thesis by simp
  qed
  show ?thesis
    apply (rule exI[of _ pieces])
    apply (rule exI[of _ gs])
    using len iso sub src images ball3_copies_disjoint
    by simp
qed

text ‹The Banach--Tarski theorem for the closed unit ball, as a partition theorem.›
theorem banach_tarski:
  "∃P :: (real^3) set list. ∃gs :: ((real^3) ⇒ (real^3)) list.
       length P = length gs ∧
       (∀g ∈ set gs. isometry g) ∧
       pairwise_disjoint P ∧
       pairwise_disjoint (map2 (λg A. g ` A) gs P) ∧
       (∀i < length P. P ! i ⊆ ball3) ∧
       ball3 = (⋃i<length P. P ! i) ∧
       (ball3_copy_left ∪ ball3_copy_right) =
         (⋃i<length P. (gs ! i) ` (P ! i)) ∧
       ball3_copy_left ∩ ball3_copy_right = {}"
proof -
  from ball3_paradoxical_strong obtain P Q :: "(real^3) set list"
    and gP gQ :: "((real^3 ⇒ real^3)) list"
    where lenP: "length P = length gP"
      and lenQ: "length Q = length gQ"
      and gP_iso: "∀g ∈ set gP. isometry g"
      and gQ_iso: "∀g ∈ set gQ. isometry g"
      and source_disj: "pairwise_disjoint (P @ Q)"
      and imageP_disj: "pairwise_disjoint (map2 (λg A. g ` A) gP P)"
      and imageQ_disj: "pairwise_disjoint (map2 (λg A. g ` A) gQ Q)"
      and P_sub: "∀i < length P. P ! i ⊆ ball3"
      and Q_sub: "∀i < length Q. Q ! i ⊆ ball3"
      and source_cover: "ball3 = (⋃i<length P. P ! i) ∪ (⋃i<length Q. Q ! i)"
      and P_cov: "ball3 = (⋃i<length P. (gP ! i) ` (P ! i))"
      and Q_cov: "ball3 = (⋃i<length Q. (gQ ! i) ` (Q ! i))"
    by auto
  define pieces where "pieces = P @ Q"
  define hQ where "hQ = map (λg. (+) shift3 ∘ g) gQ"
  define gs where "gs = gP @ hQ"
  have len_hQ: "length Q = length hQ"
    by (simp add: hQ_def lenQ)
  have len: "length pieces = length gs"
    by (simp add: pieces_def gs_def lenP len_hQ)
  have iso: "∀g ∈ set gs. isometry g"
    using gP_iso gQ_iso
    by (auto simp add: gs_def hQ_def isometry_compose)
  have sub: "∀i < length pieces. pieces ! i ⊆ ball3"
    using P_sub Q_sub by (auto simp add: pieces_def nth_append)
  have src: "ball3 = (⋃i<length pieces. pieces ! i)"
    by (metis indexed_union_append pieces_def source_cover)
  have source_disj_pieces: "pairwise_disjoint pieces"
    using source_disj by (simp add: pieces_def)

  have right_cov:
    "ball3_copy_right = (⋃i<length Q. (hQ ! i) ` (Q ! i))"
  proof -
    have right_union:
      "(⋃i<length Q. (hQ ! i) ` (Q ! i)) =
        (+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i))"
    proof (rule equalityI)
      show "(⋃i<length Q. (hQ ! i) ` (Q ! i)) ⊆
          (+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i))"
      proof
        fix x assume "x ∈ (⋃i<length Q. (hQ ! i) ` (Q ! i))"
        then obtain i y where i_lt: "i < length Q" and y_in: "y ∈ Q ! i"
          and x_eq: "x = (hQ ! i) y"
          by blast
        have h_eq: "hQ ! i = (+) shift3 ∘ (gQ ! i)"
          using i_lt lenQ by (simp add: hQ_def)
        have "(gQ ! i) y ∈ (⋃i<length Q. (gQ ! i) ` (Q ! i))"
          using i_lt y_in by blast
        moreover have "x = shift3 + (gQ ! i) y"
          using x_eq h_eq by simp
        ultimately show "x ∈ (+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i))"
          by blast
      qed
      show "(+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i)) ⊆
          (⋃i<length Q. (hQ ! i) ` (Q ! i))"
      proof
        fix x assume "x ∈ (+) shift3 ` (⋃i<length Q. (gQ ! i) ` (Q ! i))"
        then obtain z i y where x_eq: "x = shift3 + z"
          and i_lt: "i < length Q" and y_in: "y ∈ Q ! i" and z_eq: "z = (gQ ! i) y"
          by blast
        have h_eq: "hQ ! i = (+) shift3 ∘ (gQ ! i)"
          using i_lt lenQ by (simp add: hQ_def)
        have "x = (hQ ! i) y"
          using x_eq z_eq h_eq by simp
        thus "x ∈ (⋃i<length Q. (hQ ! i) ` (Q ! i))"
          using i_lt y_in by blast
      qed
    qed
    show ?thesis
      unfolding ball3_copy_right_def
      using right_union Q_cov by simp
  qed
  have images:
    "ball3_copy_left ∪ ball3_copy_right =
      (⋃i<length pieces. (gs ! i) ` (pieces ! i))"
  proof -
    have "(⋃i<length pieces. (gs ! i) ` (pieces ! i)) =
        (⋃i<length P. (gP ! i) ` (P ! i)) ∪
        (⋃i<length Q. (hQ ! i) ` (Q ! i))"
      unfolding pieces_def gs_def
      by (rule indexed_image_union_append[OF lenP len_hQ])
    also have "… = ball3_copy_left ∪ ball3_copy_right"
      using P_cov right_cov by (simp add: ball3_copy_left_def)
    finally show ?thesis by simp
  qed

  have shift_inj: "inj ((+) shift3)"
    by (simp add: inj_def)
  have right_image_disj: "pairwise_disjoint (map2 (λg A. g ` A) hQ Q)"
    unfolding pairwise_disjoint_def
  proof (intro allI impI)
    fix i j
    assume i: "i < length (map2 (λg A. g ` A) hQ Q)"
      and j: "j < length (map2 (λg A. g ` A) hQ Q)"
      and ij: "i ≠ j"
    have iQ: "i < length Q" and jQ: "j < length Q"
      using i j len_hQ by auto
    have base_disj: "(gQ ! i ` (Q ! i)) ∩ (gQ ! j ` (Q ! j)) = {}"
      using imageQ_disj lenQ iQ jQ ij by (simp add: pairwise_disjoint_def)
    have hi: "hQ ! i = (+) shift3 ∘ (gQ ! i)"
      using iQ lenQ by (simp add: hQ_def)
    have hj: "hQ ! j = (+) shift3 ∘ (gQ ! j)"
      using jQ lenQ by (simp add: hQ_def)
    show "map2 (λg A. g ` A) hQ Q ! i ∩ map2 (λg A. g ` A) hQ Q ! j = {}"
      using base_disj shift_inj iQ jQ len_hQ
      by (auto simp: hi hj inj_def)
  qed
  have left_sets_sub: "⋀A. A ∈ set (map2 (λg A. g ` A) gP P) ⟹ A ⊆ ball3_copy_left"
  proof -
    fix A
    assume A: "A ∈ set (map2 (λg A. g ` A) gP P)"
    then obtain i where i: "i < length P" and A_eq: "A = (gP ! i) ` (P ! i)"
      using lenP by (auto simp: in_set_conv_nth)
    have "A ⊆ (⋃i<length P. (gP ! i) ` (P ! i))"
      using i A_eq by blast
    thus "A ⊆ ball3_copy_left"
      using P_cov by (simp add: ball3_copy_left_def)
  qed
  have right_sets_sub: "⋀A. A ∈ set (map2 (λg A. g ` A) hQ Q) ⟹ A ⊆ ball3_copy_right"
  proof -
    fix A
    assume A: "A ∈ set (map2 (λg A. g ` A) hQ Q)"
    then obtain i where i: "i < length Q" and A_eq: "A = (hQ ! i) ` (Q ! i)"
      using len_hQ by (auto simp: in_set_conv_nth)
    have "A ⊆ (⋃i<length Q. (hQ ! i) ` (Q ! i))"
      using i A_eq by blast
    thus "A ⊆ ball3_copy_right"
      using right_cov by simp
  qed
  have image_cross_disj:
    "⋀A B. ⟦A ∈ set (map2 (λg A. g ` A) gP P);
      B ∈ set (map2 (λg A. g ` A) hQ Q)⟧ ⟹ A ∩ B = {}"
  proof -
    fix A B
    assume A: "A ∈ set (map2 (λg A. g ` A) gP P)"
      and B: "B ∈ set (map2 (λg A. g ` A) hQ Q)"
    have "A ∩ B ⊆ ball3_copy_left ∩ ball3_copy_right"
      using left_sets_sub[OF A] right_sets_sub[OF B] by blast
    thus "A ∩ B = {}"
      using ball3_copies_disjoint by blast
  qed
  have image_disj: "pairwise_disjoint (map2 (λg A. g ` A) gs pieces)"
    unfolding gs_def pieces_def
    using pairwise_disjoint_appendI[OF imageP_disj right_image_disj image_cross_disj]
    using lenP by fastforce
  show ?thesis
  proof (intro exI conjI)
    show "length pieces = length gs"
      by (rule len)
    show "∀g∈set gs. isometry g"
      by (rule iso)
    show "pairwise_disjoint pieces"
      by (rule source_disj_pieces)
    show "pairwise_disjoint (map2 (λg A. g ` A) gs pieces)"
      by (rule image_disj)
    show "∀i<length pieces. pieces ! i ⊆ ball3"
      by (rule sub)
    show "ball3 = (⋃i<length pieces. pieces ! i)"
      by (rule src)
    show "ball3_copy_left ∪ ball3_copy_right =
        (⋃i<length pieces. (gs ! i) ` (pieces ! i))"
      by (rule images)
    show "ball3_copy_left ∩ ball3_copy_right = {}"
      by (rule ball3_copies_disjoint)
  qed
qed

end