Theory Sphere_Decomposition

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

    Paradoxical decomposition of the entire two-sphere
    ‹S2›, by absorbing the "bad set" of fixed points via a
    standard translation argument.

    Sketch (the classical absorption argument):
      pick a rotation ‹R ∈ SO(3)› of infinite order whose axis
      avoids the bad set and such that ‹D›, ‹R D›,
      ‹R2 D›, … are pairwise disjoint;
      let ‹E = D ∪ R D ∪ R2 D ∪ …›;
      then ‹S2 ∖ D› and ‹S2› are
      equidecomposable via ‹E ↦ R E›.

    The absorbing rotation is constructed by avoiding countably many
    forbidden collision angles.
*)

theory Sphere_Decomposition
  imports Hausdorff_Paradox
begin

text ‹
  Equidecomposability of S2 ∖ D› and S2.
›

definition Rz_angle_mat :: "real  real^3^3" where
  "Rz_angle_mat t = vector [
     vector [cos t, - sin t, 0],
     vector [sin t, cos t, 0],
     vector [0, 0, 1]]"

definition Rz_angle :: "real  real^3  real^3" where
  "Rz_angle t v = Rz_angle_mat t *v v"

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

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

lemma Rz_angle_mat_orthogonal: "orthogonal_matrix (Rz_angle_mat t)"
  unfolding orthogonal_matrix Rz_angle_mat_def
  by (simp add: matrix_matrix_mult_def transpose_def mat_def vec_eq_iff vector_def sum_3 forall_3
      power2_eq_square algebra_simps)

lemma det_Rz_angle_mat [simp]: "det (Rz_angle_mat t) = 1"
  unfolding Rz_angle_mat_def
  by (simp add: det_3 vector_def power2_eq_square algebra_simps)

lemma Rz_angle_in_SO3: "Rz_angle t  SO3"
  unfolding SO3_def rotation_def Rz_angle_def
  by (simp add: orthogonal_transformation_matrix Rz_angle_mat_orthogonal matrix_vector_mul_linear)

lemma Rz_angle_mat_add:
  "Rz_angle_mat a ** Rz_angle_mat b = Rz_angle_mat (a + b)"
  unfolding Rz_angle_mat_def
  by (simp add: matrix_matrix_mult_def vec_eq_iff vector_def sum_3 forall_3
      cos_add sin_add algebra_simps)

lemma Rz_angle_compose:
  "Rz_angle a  Rz_angle b = Rz_angle (a + b)"
  by (rule ext) (simp add: Rz_angle_def matrix_vector_mul_assoc Rz_angle_mat_add)

lemma Rz_angle_funpow:
  "(Rz_angle t ^^ n) = Rz_angle (real n * t)"
proof (induction n)
  case 0
  show ?case
    by (rule ext) (simp add: Rz_angle_def Rz_angle_mat_def mat_def matrix_vector_mult_def
        vec_eq_iff vector_def forall_3 sum_3)
next
  case (Suc n)
  have "(Rz_angle t ^^ Suc n) = Rz_angle t  Rz_angle (real n * t)"
    using Suc.IH by simp
  also have " = Rz_angle (t + real n * t)"
    by (rule Rz_angle_compose)
  also have "t + real n * t = real (Suc n) * t"
    by (simp add: algebra_simps)
  finally show ?case .
qed

lemma Rz_angle_components [simp]:
  "(Rz_angle t x) $ 1 = cos t * x $ 1 - sin t * x $ 2"
  "(Rz_angle t x) $ 2 = sin t * x $ 1 + cos t * x $ 2"
  "(Rz_angle t x) $ 3 = x $ 3"
  by (simp_all add: Rz_angle_def Rz_angle_mat_def matrix_vector_mult_def
      vector_def sum_3)

lemma Rz_angle_eq_non_axis_sin_cos:
  assumes "Rz_angle a x = Rz_angle b x" and "x $ 1  0  x $ 2  0"
  shows "sin a = sin b  cos a = cos b"
proof -
  let ?X = "x $ 1"
  let ?Y = "x $ 2"
  let ?C = "cos a - cos b"
  let ?S = "sin a - sin b"
  have comp1: "(Rz_angle a x) $ 1 = (Rz_angle b x) $ 1"
    using arg_cong[OF assms(1), of "λv. v $ 1"] .
  have comp2: "(Rz_angle a x) $ 2 = (Rz_angle b x) $ 2"
    using arg_cong[OF assms(1), of "λv. v $ 2"] .
  have eq1: "?C * ?X - ?S * ?Y = 0"
    using comp1 by (simp add: algebra_simps)
  have eq2: "?S * ?X + ?C * ?Y = 0"
    using comp2 by (simp add: algebra_simps)
  have nonzero: "?X2 + ?Y2  0"
    using assms(2) by (simp add: power2_eq_square sum_squares_eq_zero_iff)
  have C_eq: "?C * (?X2 + ?Y2) =
      (?C * ?X - ?S * ?Y) * ?X + (?S * ?X + ?C * ?Y) * ?Y"
    by (simp add: power2_eq_square algebra_simps)
  have Cprod0: "?C * (?X2 + ?Y2) = 0"
    using C_eq eq1 eq2 by simp
  hence C_or: "?C = 0  ?X2 + ?Y2 = 0"
    by (simp add: mult_eq_0_iff)
  have C0: "?C = 0"
    using C_or nonzero by blast
  have S_eq: "?S * (?X2 + ?Y2) =
      (?S * ?X + ?C * ?Y) * ?X - (?C * ?X - ?S * ?Y) * ?Y"
    by (simp add: power2_eq_square algebra_simps)
  have Sprod0: "?S * (?X2 + ?Y2) = 0"
    using S_eq eq1 eq2 by simp
  hence S_or: "?S = 0  ?X2 + ?Y2 = 0"
    by (simp add: mult_eq_0_iff)
  have S0: "?S = 0"
    using S_or nonzero by blast
  from S0 C0 show ?thesis
    by simp
qed

lemma Rz_angle_collision_angles_countable:
  assumes nonaxis: "x $ 1  0  x $ 2  0"
  shows "countable {t. Rz_angle t x = y}"
proof (cases "{t. Rz_angle t x = y} = {}")
  case True
  then show ?thesis by simp
next
  case False
  then obtain a where a: "Rz_angle a x = y"
    by auto
  have subset: "{t. Rz_angle t x = y}  (λn::int. a + 2 * pi * n) ` UNIV"
  proof
    fix t
    assume t: "t  {t. Rz_angle t x = y}"
    hence eq: "Rz_angle t x = Rz_angle a x"
      using a by simp
    have trig: "sin t = sin a  cos t = cos a"
      by (rule Rz_angle_eq_non_axis_sin_cos[OF eq nonaxis])
    have "n::int. t = a + 2 * pi * n"
      using iffD1[OF sin_cos_eq_iff[of t a] trig] .
    then obtain n :: int where n: "t = a + 2 * pi * n"
      by blast
    show "t  (λn::int. a + 2 * pi * n) ` UNIV"
      using n by simp
  qed
  have "countable ((λn::int. a + 2 * pi * n) ` UNIV)"
    by simp
  thus ?thesis
    by (rule countable_subset[OF subset])
qed

lemma Rz_angle_scaled_collision_angles_countable:
  assumes "k > 0" and nonaxis: "x $ 1  0  x $ 2  0"
  shows "countable {t. Rz_angle (real k * t) x = y}"
proof -
  let ?f = "λt::real. real k * t"
  let ?A = "{u. Rz_angle u x = y}"
  have count_A: "countable ?A"
    by (rule Rz_angle_collision_angles_countable[OF nonaxis])
  have inj_f: "inj_on ?f UNIV"
    using assms(1) by (auto simp: inj_on_def)
  have count_pre: "countable {t  UNIV. ?f t  ?A}"
    by (rule countable_image_inj_gen[OF inj_f count_A])
  thus ?thesis
    by simp
qed

lemma e1_3_in_sphere2: "e1_3  sphere2"
  by (simp add: e1_3_def sphere2_def norm_eq_1 inner_vec_def sum_3 vector_def)

lemma e1_3_nonaxis: "e1_3 $ 1  0  e1_3 $ 2  0"
  by (simp add: e1_3_def)

lemma e3_3_in_sphere2: "e3_3  sphere2"
  by (simp add: e3_3_def sphere2_def norm_eq_1 inner_vec_def sum_3 vector_def)

lemma z_axis_sphere2_cases:
  assumes "x  sphere2" and "x $ 1 = 0" and "x $ 2 = 0"
  shows "x = e3_3  x = - e3_3"
proof -
  have x3_sq: "(x $ 3)2 = 1"
    using assms unfolding sphere2_def
    by (simp add: norm_eq_1 inner_vec_def sum_3 power2_eq_square)
  hence "x $ 3 = 1  x $ 3 = -1"
    by (simp add: power2_eq_1_iff)
  thus ?thesis
    using assms(2,3)
    by (auto simp: e3_3_def vec_eq_iff vector_def forall_3)
qed

lemma SO3_funpow:
  assumes "R  SO3"
  shows "(R ^^ n)  SO3"
proof (induction n)
  case 0
  show ?case
    using id_in_SO3 by (simp add: id_def)
next
  case (Suc n)
  have "R  (R ^^ n)  SO3"
    by (rule SO3_closed_compose[OF assms Suc.IH])
  thus ?case
    by (simp add: o_def)
qed

lemma SO3_inj:
  assumes "f  SO3"
  shows "inj f"
proof -
  have "orthogonal_transformation f"
    using assms unfolding SO3_def rotation_def by auto
  thus ?thesis
    by (rule orthogonal_transformation_inj)
qed

lemma SO3_surj:
  assumes "f  SO3"
  shows "surj f"
proof -
  have "orthogonal_transformation f"
    using assms unfolding SO3_def rotation_def by auto
  thus ?thesis
    by (rule orthogonal_transformation_surj)
qed

lemma SO3_linear:
  assumes "f  SO3"
  shows "linear f"
proof -
  have "orthogonal_transformation f"
    using assms unfolding SO3_def rotation_def by auto
  thus ?thesis
    by (rule orthogonal_transformation_linear)
qed

lemma SO3_inverse:
  assumes "f  SO3"
  shows "Hilbert_Choice.inv f  SO3"
proof -
  have f_orth: "orthogonal_transformation f"
    and f_det: "det (matrix f) = 1"
    using assms unfolding SO3_def rotation_def by auto
  have inv_orth: "orthogonal_transformation (Hilbert_Choice.inv f)"
    by (rule orthogonal_transformation_inv[OF f_orth])
  have f_lin: "linear f"
    by (rule orthogonal_transformation_linear[OF f_orth])
  have inv_lin: "linear (Hilbert_Choice.inv f)"
    by (rule orthogonal_transformation_linear[OF inv_orth])
  have surj_f: "surj f"
    by (rule orthogonal_transformation_surj[OF f_orth])
  have comp_id: "f  Hilbert_Choice.inv f = id"
    using surj_f by (auto simp: fun_eq_iff surj_f_inv_f)
  have "det (matrix (f  Hilbert_Choice.inv f)) =
      det (matrix f) * det (matrix (Hilbert_Choice.inv f))"
    using matrix_compose[OF inv_lin f_lin] by (simp add: det_mul)
  also have " = det (matrix (Hilbert_Choice.inv f))"
    using f_det by simp
  finally have "det (matrix (Hilbert_Choice.inv f)) = 1"
    using comp_id by simp
  with inv_orth show ?thesis
    unfolding SO3_def rotation_def by simp
qed

lemma conjugate_funpow:
  assumes bijS: "bij S"
  shows "((S  R  Hilbert_Choice.inv S) ^^ n) =
    S  (R ^^ n)  Hilbert_Choice.inv S"
proof (induction n)
  case 0
  show ?case
    using bijS by (auto simp: fun_eq_iff bij_is_surj surj_f_inv_f)
next
  case (Suc n)
  have injS: "inj S"
    using bijS by (simp add: bij_is_inj)
  show ?case
  proof (rule ext)
    fix x
    have n_eq: "((S  R  Hilbert_Choice.inv S) ^^ n) x =
        S ((R ^^ n) (Hilbert_Choice.inv S x))"
      using fun_cong[OF Suc.IH, of x] by (simp add: o_def)
    have "((S  R  Hilbert_Choice.inv S) ^^ Suc n) x =
        S (R (Hilbert_Choice.inv S (((S  R  Hilbert_Choice.inv S) ^^ n) x)))"
      by simp
    also have " = S (R (Hilbert_Choice.inv S
        (S ((R ^^ n) (Hilbert_Choice.inv S x)))))"
      using n_eq by simp
    also have " = S ((R ^^ Suc n) (Hilbert_Choice.inv S x))"
      using injS by (simp add: inv_f_f)
    finally show "((S  R  Hilbert_Choice.inv S) ^^ Suc n) x =
        (S  (R ^^ Suc n)  Hilbert_Choice.inv S) x"
      by simp
  qed
qed

lemma conjugate_funpow_image:
  assumes bijS: "bij S"
  shows "((S  R  Hilbert_Choice.inv S) ^^ n) ` D =
    S ` ((R ^^ n) ` (Hilbert_Choice.inv S ` D))"
  using conjugate_funpow[OF bijS, of n R]
  by auto

lemma exists_antipodal_axis_avoiding_countable:
  assumes count_D: "countable D"
  shows "a  sphere2. a  D  - a  D"
proof -
  let ?A = "D  uminus ` D"
  have count_A: "countable ?A"
    using count_D by simp
  let ?bad = "(y  ?A. {t. Rz_angle t e1_3 = y})"
  have count_bad: "countable ?bad"
  proof (intro countable_UN count_A)
    fix y
    assume "y  ?A"
    show "countable {t. Rz_angle t e1_3 = y}"
      by (rule Rz_angle_collision_angles_countable[OF e1_3_nonaxis])
  qed
  obtain t where t_not_bad: "t  ?bad"
    using real_interval_avoid_countable_set[OF zero_less_one count_bad] by blast
  define a where "a = Rz_angle t e1_3"
  have a_sphere: "a  sphere2"
    unfolding a_def
    by (rule rotation_preserves_sphere2[OF Rz_angle_in_SO3 e1_3_in_sphere2])
  have a_not_A: "a  ?A"
    using t_not_bad unfolding a_def by blast
  hence a_not_D: "a  D"
    by simp
  have neg_a_not_D: "- a  D"
  proof
    assume "- a  D"
    hence "uminus (- a)  uminus ` D"
      by blast
    hence "a  uminus ` D"
      by simp
    with a_not_A show False
      by simp
  qed
  from a_sphere a_not_D neg_a_not_D show ?thesis
    by blast
qed

lemma exists_Rz_angle_absorbing:
  assumes count_D: "countable D"
    and nonaxis: "x. x  D  x $ 1  0  x $ 2  0"
  shows "t. n m. n  m  ((Rz_angle t ^^ n) ` D)  ((Rz_angle t ^^ m) ` D) = {}"
proof -
  let ?bad = "(k  {k::nat. k > 0}. x  D. y  D.
    {t. Rz_angle (real k * t) x = y})"
  have count_bad: "countable ?bad"
  proof (intro countable_UN countable_Collect countableI_type count_D)
    fix k x y
    assume "k  {k::nat. 0 < k}" and "x  D" and "y  D"
    thus "countable {t. Rz_angle (real k * t) x = y}"
      by (intro Rz_angle_scaled_collision_angles_countable nonaxis) auto
  qed
  obtain t where t_not_bad: "t  ?bad"
    using real_interval_avoid_countable_set[OF zero_less_one count_bad] by blast
  have disj: "((Rz_angle t ^^ n) ` D)  ((Rz_angle t ^^ m) ` D) = {}" if "n  m" for n m
  proof (rule ccontr)
    assume "((Rz_angle t ^^ n) ` D)  ((Rz_angle t ^^ m) ` D)  {}"
    then obtain x y z where x: "x  D" and y: "y  D"
      and z: "z = (Rz_angle t ^^ n) x" "z = (Rz_angle t ^^ m) y"
      by blast
    have False if nm: "n < m"
    proof -
      let ?k = "m - n"
      have k_pos: "?k > 0"
        using nm by simp
      have m_eq: "m = n + ?k"
        using nm by simp
      have eq: "(Rz_angle t ^^ n) x = (Rz_angle t ^^ m) y"
        using z by simp
      have tail: "(Rz_angle t ^^ m) y =
          (Rz_angle t ^^ n) ((Rz_angle t ^^ ?k) y)"
        using m_eq by (metis comp_apply funpow_add)
      have "(Rz_angle t ^^ n) x = (Rz_angle t ^^ n) ((Rz_angle t ^^ ?k) y)"
        using eq tail by simp
      moreover have "inj (Rz_angle t ^^ n)"
        by (rule SO3_inj[OF SO3_funpow[OF Rz_angle_in_SO3]])
      ultimately have x_eq: "x = (Rz_angle t ^^ ?k) y"
        by (meson injD)
      have "Rz_angle (real ?k * t) y = x"
        using x_eq Rz_angle_funpow[of ?k t] by (simp add: fun_eq_iff)
      hence "t  {u. Rz_angle (real ?k * u) y = x}"
        by simp
      hence "t  ?bad"
        using k_pos x y by blast
      with t_not_bad show False
        by contradiction
    qed
    moreover have False if mn: "m < n"
    proof -
      let ?k = "n - m"
      have k_pos: "?k > 0"
        using mn by simp
      have n_eq: "n = m + ?k"
        using mn by simp
      have eq: "(Rz_angle t ^^ m) y = (Rz_angle t ^^ n) x"
        using z by simp
      have tail: "(Rz_angle t ^^ n) x =
          (Rz_angle t ^^ m) ((Rz_angle t ^^ ?k) x)"
        using n_eq by (metis comp_apply funpow_add)
      have "(Rz_angle t ^^ m) y = (Rz_angle t ^^ m) ((Rz_angle t ^^ ?k) x)"
        using eq tail by simp
      moreover have "inj (Rz_angle t ^^ m)"
        by (rule SO3_inj[OF SO3_funpow[OF Rz_angle_in_SO3]])
      ultimately have y_eq: "y = (Rz_angle t ^^ ?k) x"
        by (meson injD)
      have "Rz_angle (real ?k * t) x = y"
        using y_eq Rz_angle_funpow[of ?k t] by (simp add: fun_eq_iff)
      hence "t  {u. Rz_angle (real ?k * u) x = y}"
        by simp
      hence "t  ?bad"
        using k_pos x y by blast
      with t_not_bad show False
        by contradiction
    qed
    ultimately show False
      using that by linarith
  qed
  show ?thesis
    using disj by blast
qed

lemma exists_absorbing_rotation:
  "R  SO3. n m. n  m  ((R^^n) ` bad_set_D)  ((R^^m) ` bad_set_D) = {}"
proof -
  obtain a where a_sphere: "a  sphere2" and a_not_D: "a  bad_set_D"
    and neg_a_not_D: "- a  bad_set_D"
    using exists_antipodal_axis_avoiding_countable[OF bad_set_D_countable] by blast
  have norm_eq: "norm e3_3 = norm a"
    using e3_3_in_sphere2 a_sphere unfolding sphere2_def by simp
  have card3: "2  CARD(3)"
    by simp
  obtain S where S_orth: "orthogonal_transformation S"
    and S_det: "det (matrix S) = 1"
    and S_e3: "S e3_3 = a"
    using rotation_exists[OF card3 norm_eq] by blast
  have S_SO3: "S  SO3"
    using S_orth S_det unfolding SO3_def rotation_def by simp
  have invS_SO3: "Hilbert_Choice.inv S  SO3"
    by (rule SO3_inverse[OF S_SO3])
  have S_bij: "bij S"
    by (rule orthogonal_transformation_bij[OF S_orth])
  have S_inj: "inj S"
    using S_bij by (simp add: bij_is_inj)
  have S_surj: "surj S"
    using S_bij by (simp add: bij_is_surj)
  have S_lin: "linear S"
    by (rule orthogonal_transformation_linear[OF S_orth])
  let ?D' = "Hilbert_Choice.inv S ` bad_set_D"
  have count_D': "countable ?D'"
    using bad_set_D_countable by simp
  have nonaxis_D': "x $ 1  0  x $ 2  0" if xD: "x  ?D'" for x
  proof (rule ccontr)
    assume "¬ (x $ 1  0  x $ 2  0)"
    hence x1: "x $ 1 = 0" and x2: "x $ 2 = 0"
      by auto
    from xD obtain d where dD: "d  bad_set_D" and x_def: "x = Hilbert_Choice.inv S d"
      by auto
    have d_sphere: "d  sphere2"
      using dD bad_set_D_subset by auto
    have x_sphere: "x  sphere2"
      unfolding x_def
      by (rule rotation_preserves_sphere2[OF invS_SO3 d_sphere])
    have axis_cases: "x = e3_3  x = - e3_3"
      by (rule z_axis_sphere2_cases[OF x_sphere x1 x2])
    have Sx_d: "S x = d"
      using x_def S_surj by (simp add: surj_f_inv_f)
    from axis_cases show False
    proof
      assume "x = e3_3"
      hence "d = a"
        using Sx_d S_e3 by simp
      with dD a_not_D show False
        by simp
    next
      assume "x = - e3_3"
      hence "S x = - a"
        using S_lin S_e3 by (simp add: linear_neg)
      hence "d = - a"
        using Sx_d by simp
      with dD neg_a_not_D show False
        by simp
    qed
  qed
  obtain t where t_disj:
    "n m. n  m 
      ((Rz_angle t ^^ n) ` ?D')  ((Rz_angle t ^^ m) ` ?D') = {}"
    using exists_Rz_angle_absorbing[OF count_D' nonaxis_D'] by blast
  let ?R = "S  Rz_angle t  Hilbert_Choice.inv S"
  have inner_SO3: "Rz_angle t  Hilbert_Choice.inv S  SO3"
    by (rule SO3_closed_compose[OF Rz_angle_in_SO3 invS_SO3])
  have R_SO3: "?R  SO3"
  proof -
    have "S  (Rz_angle t  Hilbert_Choice.inv S)  SO3"
      by (rule SO3_closed_compose[OF S_SO3 inner_SO3])
    thus ?thesis
      by (simp add: o_assoc)
  qed
  have R_disj: "((?R ^^ n) ` bad_set_D)  ((?R ^^ m) ` bad_set_D) = {}"
    if nm: "n  m" for n m
  proof -
    have n_img: "((?R ^^ n) ` bad_set_D) =
        S ` ((Rz_angle t ^^ n) ` ?D')"
      by (rule conjugate_funpow_image[OF S_bij])
    have m_img: "((?R ^^ m) ` bad_set_D) =
        S ` ((Rz_angle t ^^ m) ` ?D')"
      by (rule conjugate_funpow_image[OF S_bij])
    have z_disj: "((Rz_angle t ^^ n) ` ?D')  ((Rz_angle t ^^ m) ` ?D') = {}"
      using t_disj nm by blast
    show ?thesis
      unfolding n_img m_img
      using z_disj S_inj by (auto dest: injD)
  qed
  from R_SO3 R_disj show ?thesis
    by blast
qed

lemma SO3_funpow_preserves_sphere2:
  assumes "R  SO3" and "x  sphere2"
  shows "(R ^^ n) x  sphere2"
  by (rule rotation_preserves_sphere2[OF SO3_funpow[OF assms(1)] assms(2)])

lemma funpow_Suc_image:
  "((R ^^ Suc n) ` S) = R ` ((R ^^ n) ` S)"
  by auto

lemma absorbing_rotation_shift:
  assumes disj: "n m. n  m  ((R^^n) ` D)  ((R^^m) ` D) = {}"
  defines "E  (n. (R^^n) ` D)"
  shows "R ` E = E - D"
proof
  show "R ` E  E - D"
  proof
    fix y
    assume "y  R ` E"
    then obtain x n d where x: "x = (R ^^ n) d" and d: "d  D" and y: "y = R x"
      unfolding E_def by blast
    have y_pow: "y  (R ^^ Suc n) ` D"
      using x d y by auto
    hence "y  E"
      unfolding E_def by blast
    moreover have "y  D"
    proof
      assume "y  D"
      hence "y  (R ^^ 0) ` D"
        by simp
      with y_pow have "((R ^^ Suc n) ` D)  ((R ^^ 0) ` D)  {}"
        by blast
      moreover have "Suc n  0"
        by simp
      ultimately show False
        using disj by blast
    qed
    ultimately show "y  E - D"
      by simp
  qed
next
  show "E - D  R ` E"
  proof
    fix y
    assume y: "y  E - D"
    then obtain n d where y_pow: "y = (R ^^ n) d" and d: "d  D"
      unfolding E_def by blast
    from y have y_not_D: "y  D"
      by simp
    show "y  R ` E"
    proof (cases n)
      case 0
      with y_pow d y_not_D show ?thesis
        by simp
    next
      case (Suc k)
      have "(R ^^ k) d  E"
        unfolding E_def using d by blast
      moreover have "y = R ((R ^^ k) d)"
        using y_pow Suc by simp
      ultimately show ?thesis
        by blast
    qed
  qed
qed

lemma sphere2_absorb_bad_set:
  "P Q :: (real^3) set list. gs :: ((real^3)  (real^3)) list.
      length P = length Q  length P = length gs 
      set gs  SO3 
      sphere2 = (i<length P. P ! i) 
      (sphere2 - bad_set_D) = (i<length Q. Q ! i) 
      (i < length P. Q ! i = (gs ! i) ` (P ! i))"
proof -
  obtain R where R_SO3: "R  SO3"
    and disj: "n m. n  m  ((R^^n) ` bad_set_D)  ((R^^m) ` bad_set_D) = {}"
    using exists_absorbing_rotation by auto
  define E where "E = (n. (R^^n) ` bad_set_D)"
  have R_E: "R ` E = E - bad_set_D"
    unfolding E_def by (rule absorbing_rotation_shift[OF disj])
  have D_subset_E: "bad_set_D  E"
  proof
    fix x
    assume x: "x  bad_set_D"
    have "x  (R ^^ 0) ` bad_set_D"
      using x by (auto simp add: image_def)
    thus "x  E"
      unfolding E_def by blast
  qed
  have E_subset_sphere2: "E  sphere2"
  proof
    fix x
    assume "x  E"
    then obtain n d where x: "x = (R ^^ n) d" and d: "d  bad_set_D"
      unfolding E_def by blast
    from d have "d  sphere2"
      using bad_set_D_subset by blast
    with R_SO3 x show "x  sphere2"
      using SO3_funpow_preserves_sphere2 by blast
  qed
  let ?P = "[E, sphere2 - E]"
  let ?Q = "[R ` E, sphere2 - E]"
  let ?gs = "[R, id]"
  have P_union: "sphere2 = (i<length ?P. ?P ! i)"
  proof
    show "sphere2  (i<length ?P. ?P ! i)"
    proof
      fix x
      assume x: "x  sphere2"
      show "x  (i<length ?P. ?P ! i)"
      proof (cases "x  E")
        case True
        then show ?thesis
          by force
      next
        case False
        with x show ?thesis
          by force
      qed
    qed
  next
    show "(i<length ?P. ?P ! i)  sphere2"
    proof
      fix x
      assume x: "x  (i<length ?P. ?P ! i)"
      then obtain i where i: "i < length ?P" and xi: "x  ?P ! i"
        by blast
      have "i = 0  i = 1"
        using i by auto
      thus "x  sphere2"
      proof
        assume "i = 0"
        with xi E_subset_sphere2 show ?thesis
          by auto
      next
        assume "i = 1"
        with xi show ?thesis
          by auto
      qed
    qed
  qed
  have Q_union: "sphere2 - bad_set_D = (i<length ?Q. ?Q ! i)"
  proof
    show "sphere2 - bad_set_D  (i<length ?Q. ?Q ! i)"
    proof
      fix x
      assume x: "x  sphere2 - bad_set_D"
      show "x  (i<length ?Q. ?Q ! i)"
      proof (cases "x  E")
        case True
        with x R_E show ?thesis
          by force
      next
        case False
        with x show ?thesis
          by force
      qed
    qed
  next
    show "(i<length ?Q. ?Q ! i)  sphere2 - bad_set_D"
    proof
      fix x
      assume x: "x  (i<length ?Q. ?Q ! i)"
      then obtain i where i: "i < length ?Q" and xi: "x  ?Q ! i"
        by blast
      have "i = 0  i = 1"
        using i by auto
      thus "x  sphere2 - bad_set_D"
      proof
        assume "i = 0"
        with xi R_E E_subset_sphere2 show ?thesis
          by auto
      next
        assume "i = 1"
        with xi D_subset_E show ?thesis
          by auto
      qed
    qed
  qed
  have image_eq: "i < length ?P. ?Q ! i = (?gs ! i) ` (?P ! i)"
  proof (intro allI impI)
    fix i
    assume i: "i < length ?P"
    have "i = 0  i = 1"
      using i by auto
    thus "?Q ! i = (?gs ! i) ` (?P ! i)"
      by auto
  qed
  show ?thesis
    apply (rule exI[of _ ?P])
    apply (rule exI[of _ ?Q])
    apply (rule exI[of _ ?gs])
    using R_SO3 id_in_SO3 P_union Q_union image_eq
    by auto
qed

text ‹
  Combining the Hausdorff paradox with the absorption argument yields
  the paradoxical decomposition of the full sphere.
›

lemma sphere_indexed_union_append_singleton:
  fixes P :: "'a set list" and S :: "'a set"
  shows "(i<length (P @ [S]). (P @ [S]) ! i) =
    (i<length P. P ! i)  S"
proof -
  have "(i<length (P @ [S]). (P @ [S]) ! i) =
      (i<Suc (length P). (P @ [S]) ! i)"
    by simp
  also have " =
      (i<length P. (P @ [S]) ! i)  (P @ [S]) ! length P"
    by (simp add: lessThan_Suc Un_commute)
  also have " = (i<length P. P ! i)  S"
  proof -
    have "(i<length P. (P @ [S]) ! i) = (i<length P. P ! i)"
      by (rule SUP_cong) (simp_all add: nth_append)
    thus ?thesis by simp
  qed
  finally show ?thesis .
qed

lemma sphere_indexed_image_union_append_singleton:
  fixes P :: "'a set list" and G :: "('a  'b) list" and S :: "'a set"
    and g :: "'a  'b"
  assumes "length P = length G"
  shows "(i<length (P @ [S]). (G @ [g]) ! i ` ((P @ [S]) ! i)) =
    (i<length P. G ! i ` (P ! i))  g ` S"
proof -
  have "(i<length (P @ [S]). (G @ [g]) ! i ` ((P @ [S]) ! i)) =
      (i<Suc (length P). (G @ [g]) ! i ` ((P @ [S]) ! i))"
    by simp
  also have " =
      (i<length P. (G @ [g]) ! i ` ((P @ [S]) ! i)) 
      (G @ [g]) ! length P ` ((P @ [S]) ! length P)"
    by (simp add: lessThan_Suc Un_commute)
  also have " = (i<length P. G ! i ` (P ! i))  g ` S"
    using assms by (simp add: nth_append)
  finally show ?thesis .
qed

lemma sphere2_absorb_cover:
  assumes R_SO3: "R  SO3"
    and disj: "n m. n  m  ((R^^n) ` bad_set_D)  ((R^^m) ` bad_set_D) = {}"
    and len: "length P = length g"
    and g_SO3: "set g  SO3"
    and P_sub: "i < length P. P ! i  sphere2 - bad_set_D"
    and X_cover: "sphere2 - bad_set_D = (i<length P. (g ! i) ` (P ! i))"
  shows "P' :: (real^3) set list. g' :: ((real^3)  (real^3)) list.
      length P' = length g' 
      set g'  SO3 
      (i < length P'. P' ! i  sphere2) 
      sphere2 = (i<length P'. P' ! i) 
      sphere2 = (i<length P'. (g' ! i) ` (P' ! i))"
proof -
  define E where "E = (n. (R^^n) ` bad_set_D)"
  have R_E: "R ` E = E - bad_set_D"
    unfolding E_def by (rule absorbing_rotation_shift[OF disj])
  have D_subset_E: "bad_set_D  E"
  proof
    fix x
    assume x: "x  bad_set_D"
    have "x  (R ^^ 0) ` bad_set_D"
      using x by (auto simp add: image_def)
    thus "x  E"
      unfolding E_def by blast
  qed
  have E_subset_sphere2: "E  sphere2"
  proof
    fix x
    assume "x  E"
    then obtain n d where x: "x = (R ^^ n) d" and d: "d  bad_set_D"
      unfolding E_def by blast
    from d have "d  sphere2"
      using bad_set_D_subset by blast
    with R_SO3 x show "x  sphere2"
      using SO3_funpow_preserves_sphere2 by blast
  qed
  have invR_SO3: "Hilbert_Choice.inv R  SO3"
    by (rule SO3_inverse[OF R_SO3])
  have R_inj: "inj R"
    by (rule SO3_inj[OF R_SO3])
  define P0 where "P0 = P @ P"
  define g0 where "g0 = map (λh. Hilbert_Choice.inv R  h) g @ g"
  define Rest where "Rest = sphere2 - (i<length P0. P0 ! i)"
  define P' where "P' = P0 @ [Rest]"
  define g' where "g' = g0 @ [id]"
  have len0: "length P0 = length g0"
    using len by (simp add: P0_def g0_def)
  have len': "length P' = length g'"
    using len0 by (simp add: P'_def g'_def)
  have g0_SO3: "set g0  SO3"
  proof
    fix h
    assume "h  set g0"
    hence "h  (λk. Hilbert_Choice.inv R  k) ` set g  h  set g"
      by (auto simp: g0_def)
    thus "h  SO3"
    proof
      assume "h  (λk. Hilbert_Choice.inv R  k) ` set g"
      then obtain k where k: "k  set g" and h: "h = Hilbert_Choice.inv R  k"
        by blast
      have k_SO3: "k  SO3"
        using g_SO3 k by auto
      show ?thesis
        unfolding h by (rule SO3_closed_compose[OF invR_SO3 k_SO3])
    next
      assume "h  set g"
      thus ?thesis
        using g_SO3 by auto
    qed
  qed
  have g'_SO3: "set g'  SO3"
    using g0_SO3 id_in_SO3 by (auto simp: g'_def)
  have P0_sub: "i < length P0. P0 ! i  sphere2"
  proof (intro allI impI)
    fix i
    assume i: "i < length P0"
    show "P0 ! i  sphere2"
    proof (cases "i < length P")
      case True
      have P0_i: "P0 ! i = P ! i"
        using True by (simp add: P0_def nth_append)
      have "P ! i  sphere2"
        using P_sub True by blast
      thus ?thesis
        by (simp add: P0_i)
    next
      case False
      hence i2: "i - length P < length P"
        using i by (simp add: P0_def)
      have "P0 ! i = P ! (i - length P)"
        using False i by (simp add: P0_def nth_append)
      with P_sub i2 show ?thesis
        by auto
    qed
  qed
  have P'_sub: "i < length P'. P' ! i  sphere2"
  proof (intro allI impI)
    fix i
    assume i: "i < length P'"
    show "P' ! i  sphere2"
    proof (cases "i < length P0")
      case True
      have P'_i: "P' ! i = P0 ! i"
        using True by (simp add: P'_def nth_append)
      have "P0 ! i  sphere2"
        using P0_sub True by blast
      thus ?thesis
        by (simp add: P'_i)
    next
      case False
      with i have "i = length P0"
        by (simp add: P'_def)
      thus ?thesis
        by (auto simp: P'_def Rest_def)
    qed
  qed
  have P'_cover: "sphere2 = (i<length P'. P' ! i)"
  proof -
    have "(i<length P'. P' ! i) =
        (i<length P0. P0 ! i)  Rest"
      unfolding P'_def by (rule sphere_indexed_union_append_singleton)
    also have " = sphere2"
    proof
      show "(i<length P0. P0 ! i)  Rest  sphere2"
        using P0_sub by (auto simp: Rest_def)
      show "sphere2  (i<length P0. P0 ! i)  Rest"
        by (auto simp: Rest_def)
    qed
    finally show ?thesis
      by simp
  qed
  have image0_cover: "sphere2  (i<length P0. (g0 ! i) ` (P0 ! i))"
  proof
    fix y
    assume y_sphere: "y  sphere2"
    show "y  (i<length P0. (g0 ! i) ` (P0 ! i))"
    proof (cases "y  E")
      case True
      hence Ry_in_RE: "R y  R ` E"
        by blast
      have Ry_E_minus_D: "R y  E - bad_set_D"
        using Ry_in_RE R_E by simp
      have Ry_X: "R y  sphere2 - bad_set_D"
      proof
        show "R y  sphere2"
          using Ry_E_minus_D E_subset_sphere2 by blast
        show "R y  bad_set_D"
          using Ry_E_minus_D by simp
      qed
      then obtain i x where i: "i < length P" and x: "x  P ! i"
        and Ry: "R y = (g ! i) x"
        using X_cover by blast
      have i0: "i < length P0"
        using i by (simp add: P0_def)
      have g0_i: "g0 ! i = Hilbert_Choice.inv R  (g ! i)"
        using i len by (simp add: g0_def nth_append)
      have P0_i: "P0 ! i = P ! i"
        using i by (simp add: P0_def nth_append)
      have "(g0 ! i) x = y"
      proof -
        have inv_Ry: "Hilbert_Choice.inv R (R y) = y"
          by (rule inv_f_f[OF R_inj])
        have "(g0 ! i) x = Hilbert_Choice.inv R ((g ! i) x)"
          by (simp add: g0_i)
        also have " = Hilbert_Choice.inv R (R y)"
          using Ry by simp
        also have " = y"
          by (rule inv_Ry)
        finally show ?thesis .
      qed
      moreover have "(g0 ! i) x  (g0 ! i) ` (P0 ! i)"
        using x P0_i by blast
      ultimately show ?thesis
        using i0 by blast
    next
      case False
      have y_X: "y  sphere2 - bad_set_D"
      proof
        show "y  sphere2"
          by (rule y_sphere)
        show "y  bad_set_D"
          using False D_subset_E by auto
      qed
      then obtain i x where i: "i < length P" and x: "x  P ! i"
        and y_eq: "y = (g ! i) x"
        using X_cover by blast
      let ?j = "length P + i"
      have j0: "?j < length P0"
        using i by (simp add: P0_def)
      have g0_j: "g0 ! ?j = g ! i"
        using i len by (simp add: g0_def nth_append)
      have P0_j: "P0 ! ?j = P ! i"
        using i by (simp add: P0_def nth_append)
      show ?thesis
      proof -
        have "(g0 ! ?j) x  (g0 ! ?j) ` (P0 ! ?j)"
          using x P0_j by blast
        moreover have "(g0 ! ?j) x = y"
          using y_eq g0_j by simp
        ultimately show ?thesis
          using j0 by blast
      qed
    qed
  qed
  have image0_subset: "(i<length P0. (g0 ! i) ` (P0 ! i))  sphere2"
  proof
    fix y
    assume "y  (i<length P0. (g0 ! i) ` (P0 ! i))"
    then obtain i x where i: "i < length P0" and x: "x  P0 ! i"
      and y: "y = (g0 ! i) x"
      by blast
    have g0_i: "g0 ! i  SO3"
    proof -
      have "g0 ! i  set g0"
        using i len0 by (simp add: nth_mem)
      thus ?thesis
        using g0_SO3 by blast
    qed
    have x_sphere: "x  sphere2"
      using P0_sub i x by auto
    show "y  sphere2"
      using rotation_preserves_sphere2[OF g0_i x_sphere] y by simp
  qed
  have image0_eq: "sphere2 = (i<length P0. (g0 ! i) ` (P0 ! i))"
  proof
    show "sphere2  (i<length P0. (g0 ! i) ` (P0 ! i))"
      by (rule image0_cover)
    show "(i<length P0. (g0 ! i) ` (P0 ! i))  sphere2"
      by (rule image0_subset)
  qed
  have image_cover: "sphere2 = (i<length P'. (g' ! i) ` (P' ! i))"
  proof -
    have "(i<length P'. (g' ! i) ` (P' ! i)) =
        (i<length P0. (g0 ! i) ` (P0 ! i))  id ` Rest"
      unfolding P'_def g'_def
      by (rule sphere_indexed_image_union_append_singleton[OF len0])
    also have " = sphere2"
    proof -
      have "id ` Rest  sphere2"
        by (auto simp: Rest_def)
      with image0_eq show ?thesis
        by blast
    qed
    finally show ?thesis
      by simp
  qed
  show ?thesis
  proof (intro exI conjI)
    show "length P' = length g'"
      by (rule len')
    show "set g'  SO3"
      by (rule g'_SO3)
    show "i<length P'. P' ! i  sphere2"
      by (rule P'_sub)
    show "sphere2 = (i<length P'. P' ! i)"
      by (rule P'_cover)
    show "sphere2 = (i<length P'. (g' ! i) ` (P' ! i))"
      by (rule image_cover)
  qed
qed

theorem sphere2_paradoxical_strong:
  "P Q :: (real^3) set list. gP gQ :: ((real^3)  (real^3)) list.
       length P = length gP  length Q = length gQ 
       set gP  SO3  set gQ  SO3 
       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  sphere2) 
       (i < length Q. Q ! i  sphere2) 
       sphere2 = (i<length P. P ! i)  (i<length Q. Q ! i) 
       sphere2 = (i<length P. (gP ! i) ` (P ! i)) 
       sphere2 = (i<length Q. (gQ ! i) ` (Q ! i))"
proof -
  obtain R where R_SO3: "R  SO3"
    and disj: "n m. n  m  ((R^^n) ` bad_set_D)  ((R^^m) ` bad_set_D) = {}"
    using exists_absorbing_rotation by blast
  define E where "E = (n. (R^^n) ` bad_set_D)"
  have R_E: "R ` E = E - bad_set_D"
    unfolding E_def by (rule absorbing_rotation_shift[OF disj])
  have D_subset_E: "bad_set_D  E"
  proof
    fix x
    assume x: "x  bad_set_D"
    have "x  (R ^^ 0) ` bad_set_D"
      using x by (auto simp add: image_def)
    thus "x  E"
      unfolding E_def by blast
  qed
  have E_subset_sphere2: "E  sphere2"
  proof
    fix x
    assume "x  E"
    then obtain n d where x: "x = (R ^^ n) d" and d: "d  bad_set_D"
      unfolding E_def by blast
    from d have "d  sphere2"
      using bad_set_D_subset by blast
    with R_SO3 x show "x  sphere2"
      using SO3_funpow_preserves_sphere2 by blast
  qed
  have invR_SO3: "Hilbert_Choice.inv R  SO3"
    by (rule SO3_inverse[OF R_SO3])
  have R_inj: "inj R"
    by (rule SO3_inj[OF R_SO3])
  let ?X = "sphere2 - bad_set_D"
  let ?Y = "sphere2"
  let ?A = "[E, sphere2 - E]"
  let ?B = "[R ` E, sphere2 - E]"
  let ?e = "[R, id]"
  let ?t = "[Hilbert_Choice.inv R, id]"
  have A_cover: "?Y = (k<length ?A. ?A ! k)"
    using E_subset_sphere2 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 R_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 R_E E_subset_sphere2 show ?thesis
          by auto
      next
        assume "k = 1"
        with xk D_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 R_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 show ?thesis
        using inv_f_f[OF R_inj, of x] 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 = R x"
        using y by auto
      have inv_eq: "Hilbert_Choice.inv R y = x"
        using y_eq inv_f_f[OF R_inj, of x] by simp
      with x y_eq k = 0 show ?thesis
        by simp
    next
      assume "k = 1"
      with y show ?thesis
        by auto
    qed
  qed

  from hausdorff_paradox_rot_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)"
  proof -
    fix i assume i: "i < length P"
    have "gP ! i  SO3"
    proof -
      have "i < length gP"
        using lenP i by simp
      hence "gP ! i  set gP"
        by (rule nth_mem)
      thus ?thesis
        using gP_SO3 by blast
    qed
    thus "inj (gP ! i)"
      by (rule SO3_inj)
  qed
  have gQ_inj: "i. i < length Q  inj (gQ ! i)"
  proof -
    fix i assume i: "i < length Q"
    have "gQ ! i  SO3"
    proof -
      have "i < length gQ"
        using lenQ i by simp
      hence "gQ ! i  set gQ"
        by (rule nth_mem)
      thus ?thesis
        using gQ_SO3 by blast
    qed
    thus "inj (gQ ! i)"
      by (rule SO3_inj)
  qed
  have mapsP: "k i l. k < length ?A; i < length P; l < length ?B
       transfer_map ?t gP ?e k i l  SO3"
  proof -
    fix k i l
    assume k: "k < length ?A" and i: "i < length P" and l: "l < length ?B"
    have gi: "gP ! i  SO3"
    proof -
      have "i < length gP"
        using lenP i by simp
      hence "gP ! i  set gP"
        by (rule nth_mem)
      thus ?thesis
        using gP_SO3 by blast
    qed
    have ek: "?e ! k  SO3"
    proof -
      have "k = 0  k = 1"
        using k by auto
      thus ?thesis
        using R_SO3 id_in_SO3 by auto
    qed
    have tl: "?t ! l  SO3"
    proof -
      have "l = 0  l = 1"
        using l by auto
      thus ?thesis
        using invR_SO3 id_in_SO3 by auto
    qed
    have left: "(?t ! l)  (gP ! i)  SO3"
      by (rule SO3_closed_compose[OF tl gi])
    show "transfer_map ?t gP ?e k i l  SO3"
      unfolding transfer_map_def
      by (rule SO3_closed_compose[OF left ek])
  qed
  have mapsQ: "k i l. k < length ?A; i < length Q; l < length ?B
       transfer_map ?t gQ ?e k i l  SO3"
  proof -
    fix k i l
    assume k: "k < length ?A" and i: "i < length Q" and l: "l < length ?B"
    have gi: "gQ ! i  SO3"
    proof -
      have "i < length gQ"
        using lenQ i by simp
      hence "gQ ! i  set gQ"
        by (rule nth_mem)
      thus ?thesis
        using gQ_SO3 by blast
    qed
    have ek: "?e ! k  SO3"
    proof -
      have "k = 0  k = 1"
        using k by auto
      thus ?thesis
        using R_SO3 id_in_SO3 by auto
    qed
    have tl: "?t ! l  SO3"
    proof -
      have "l = 0  l = 1"
        using l by auto
      thus ?thesis
        using invR_SO3 id_in_SO3 by auto
    qed
    have left: "(?t ! l)  (gQ ! i)  SO3"
      by (rule SO3_closed_compose[OF tl gi])
    show "transfer_map ?t gQ ?e k i l  SO3"
      unfolding transfer_map_def
      by (rule SO3_closed_compose[OF left ek])
  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_SO3: "set hP  SO3"
      and hQ_SO3: "set hQ  SO3"
      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  sphere2"
    using source_cover' by blast
  have Q'_sub: "i < length Q'. Q' ! i  sphere2"
    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 "set hP  SO3"
      by (rule hP_SO3)
    show "set hQ  SO3"
      by (rule hQ_SO3)
    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  sphere2"
      by (rule P'_sub)
    show "i<length Q'. Q' ! i  sphere2"
      by (rule Q'_sub)
    show "sphere2 = (i<length P'. P' ! i)  (i<length Q'. Q' ! i)"
      by (rule source_cover')
    show "sphere2 = (i<length P'. (hP ! i) ` (P' ! i))"
      by (rule imageP_cover')
    show "sphere2 = (i<length Q'. (hQ ! i) ` (Q' ! i))"
      by (rule imageQ_cover')
  qed
qed

theorem sphere2_paradoxical:
  "P Q :: (real^3) set list. gP gQ :: ((real^3)  (real^3)) list.
       length P = length gP  length Q = length gQ 
       set gP  SO3  set gQ  SO3 
       (i < length P. P ! i  sphere2) 
       (i < length Q. Q ! i  sphere2) 
       sphere2 = (i<length P. P ! i) 
       sphere2 = (i<length Q. Q ! i) 
       sphere2 = (i<length P. (gP ! i) ` (P ! i)) 
       sphere2 = (i<length Q. (gQ ! i) ` (Q ! i))"
proof -
  obtain R where R_SO3: "R  SO3"
    and disj: "n m. n  m  ((R^^n) ` bad_set_D)  ((R^^m) ` bad_set_D) = {}"
    using exists_absorbing_rotation by blast
  from hausdorff_paradox obtain P Q :: "(real^3) set list"
    and hP hQ :: "((real^3)  (real^3)) list"
    where hd:
      "length P = length hP  length Q = length hQ 
       set hP  SO3  set hQ  SO3 
       (i < length P. P ! i  sphere2 - bad_set_D) 
       (i < length Q. Q ! i  sphere2 - bad_set_D) 
       sphere2 - bad_set_D = (i<length P. (hP ! i) ` (P ! i)) 
       sphere2 - bad_set_D = (i<length Q. (hQ ! i) ` (Q ! i))"
    by (elim exE)
  from hd have lenP: "length P = length hP"
    by (elim conjE)
  from hd have lenQ: "length Q = length hQ"
    by (elim conjE)
  from hd have hP_SO3: "set hP  SO3"
    by (elim conjE)
  from hd have hQ_SO3: "set hQ  SO3"
    by (elim conjE)
  from hd have P_sub: "i < length P. P ! i  sphere2 - bad_set_D"
    by (elim conjE)
  from hd have Q_sub: "i < length Q. Q ! i  sphere2 - bad_set_D"
    by (elim conjE)
  from hd have coverP: "sphere2 - bad_set_D = (i<length P. (hP ! i) ` (P ! i))"
    by (elim conjE)
  from hd have coverQ: "sphere2 - bad_set_D = (i<length Q. (hQ ! i) ` (Q ! i))"
    by (elim conjE)
  from sphere2_absorb_cover[OF R_SO3 disj lenP hP_SO3 P_sub coverP]
  obtain P' hP' where P'_all:
      "length P' = length hP' 
      set hP'  SO3 
      (i < length P'. P' ! i  sphere2) 
      sphere2 = (i<length P'. P' ! i) 
      sphere2 = (i<length P'. (hP' ! i) ` (P' ! i))"
    by (elim exE)
  from P'_all have P'_len: "length P' = length hP'"
    by (elim conjE)
  from P'_all have P'_SO3: "set hP'  SO3"
    by (elim conjE)
  from P'_all have P'_sub: "i < length P'. P' ! i  sphere2"
    by (elim conjE)
  from P'_all have P'_src: "sphere2 = (i<length P'. P' ! i)"
    by (elim conjE)
  from P'_all have P'_img: "sphere2 = (i<length P'. (hP' ! i) ` (P' ! i))"
    by (elim conjE)
  from sphere2_absorb_cover[OF R_SO3 disj lenQ hQ_SO3 Q_sub coverQ]
  obtain Q' hQ' where Q'_all:
      "length Q' = length hQ' 
      set hQ'  SO3 
      (i < length Q'. Q' ! i  sphere2) 
      sphere2 = (i<length Q'. Q' ! i) 
      sphere2 = (i<length Q'. (hQ' ! i) ` (Q' ! i))"
    by (elim exE)
  from Q'_all have Q'_len: "length Q' = length hQ'"
    by (elim conjE)
  from Q'_all have Q'_SO3: "set hQ'  SO3"
    by (elim conjE)
  from Q'_all have Q'_sub: "i < length Q'. Q' ! i  sphere2"
    by (elim conjE)
  from Q'_all have Q'_src: "sphere2 = (i<length Q'. Q' ! i)"
    by (elim conjE)
  from Q'_all have Q'_img: "sphere2 = (i<length Q'. (hQ' ! i) ` (Q' ! i))"
    by (elim conjE)
  show ?thesis
  proof (intro exI conjI)
    show "length P' = length hP'"
      by (rule P'_len)
    show "length Q' = length hQ'"
      by (rule Q'_len)
    show "set hP'  SO3"
      by (rule P'_SO3)
    show "set hQ'  SO3"
      by (rule Q'_SO3)
    show "i<length P'. P' ! i  sphere2"
      by (rule P'_sub)
    show "i<length Q'. Q' ! i  sphere2"
      by (rule Q'_sub)
    show "sphere2 = (i<length P'. P' ! i)"
      by (rule P'_src)
    show "sphere2 = (i<length Q'. Q' ! i)"
      by (rule Q'_src)
    show "sphere2 = (i<length P'. (hP' ! i) ` (P' ! i))"
      by (rule P'_img)
    show "sphere2 = (i<length Q'. (hQ' ! i) ` (Q' ! i))"
      by (rule Q'_img)
  qed
qed

end