Theory BT_Prelim

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

    Preliminaries shared across the Banach-Tarski formalization.

    This theory introduces conventions used throughout: type abbreviations
    for the unit sphere and unit ball, and a few small structural lemmas
    that recur.
*)

theory BT_Prelim
  imports
    "HOL-Analysis.Analysis"
    "Free-Groups.FreeGroups"
begin

section ‹The unit sphere and unit ball in $\mathbb{R}^3$›

text ‹
  We work throughout with vectors in @{typ "real^3"} (the type
  @{typ "real^3"} from theoryHOL-Analysis.Cartesian_Euclidean_Space).
  These abbreviations name the principal geometric objects of interest.
›

definition sphere2 :: "(real^3) set" where
  "sphere2 = {x. norm x = 1}"

definition ball3 :: "(real^3) set" where
  "ball3 = {x. norm x  1}"

lemma sphere2_subset_ball3: "sphere2  ball3"
  by (auto simp: sphere2_def ball3_def)

lemma zero_in_ball3: "0  ball3"
  by (simp add: ball3_def)

lemma zero_notin_sphere2: "(0::real^3)  sphere2"
  by (simp add: sphere2_def)


section ‹Disjoint finite covers›

text ‹
  A ‹partition› of a set into a finite list of pairwise disjoint pieces
  is the basic combinatorial object underlying ``equidecomposability''.
›

definition pairwise_disjoint :: "'a set list  bool" where
  "pairwise_disjoint Xs 
     (i < length Xs. j < length Xs. i  j  Xs ! i  Xs ! j = {})"

lemma pairwise_disjoint_Nil [simp]: "pairwise_disjoint []"
  by (simp add: pairwise_disjoint_def)

lemma pairwise_disjoint_singleton [simp]: "pairwise_disjoint [X]"
  by (simp add: pairwise_disjoint_def)

lemma pairwise_disjoint_nthD:
  assumes "pairwise_disjoint Xs"
    and "i < length Xs" and "j < length Xs" and "i  j"
  shows "Xs ! i  Xs ! j = {}"
  using assms bot_set_def pairwise_disjoint_def by auto

lemma indexed_union_set:
  fixes P :: "'a set list"
  shows "(i<length P. P ! i) = (set P)"
  by (auto simp add: set_conv_nth image_def)

lemma indexed_union_append:
  fixes P Q :: "'a set list"
  shows "(i<length (P @ Q). (P @ Q) ! i) =
    (i<length P. P ! i)  (i<length Q. Q ! i)"
  by (metis Union_Un_distrib indexed_union_set set_append)

lemma indexed_image_union_zip:
  fixes P :: "'a set list" and G :: "('a  'b) list"
  assumes "length P = length G"
  shows "(i<length P. G ! i ` (P ! i)) =
    ((g, A)set (zip G P). g ` A)"
  using assms by (auto simp add: set_zip)

lemma indexed_image_union_append:
  fixes P Q :: "'a set list" and G H :: "('a  'b) list"
  assumes lenP: "length P = length G" and lenQ: "length Q = length H"
  shows "(i<length (P @ Q). (G @ H) ! i ` ((P @ Q) ! i)) =
    (i<length P. G ! i ` (P ! i)) 
    (i<length Q. H ! i ` (Q ! i))"
proof -
  have len_append: "length (P @ Q) = length (G @ H)"
    using lenP lenQ by simp
  have "(i<length (P @ Q). (G @ H) ! i ` ((P @ Q) ! i)) =
      ((g, A)set (zip (G @ H) (P @ Q)). g ` A)"
    using indexed_image_union_zip[OF len_append] .
  also have " =
      ((g, A)set (zip G P). g ` A) 
      ((g, A)set (zip H Q). g ` A)"
    using lenP by simp
  also have " =
      (i<length P. G ! i ` (P ! i)) 
      (i<length Q. H ! i ` (Q ! i))"
    using indexed_image_union_zip[OF lenP] indexed_image_union_zip[OF lenQ] by simp
  finally show ?thesis .
qed

lemma indexed_union_map_fst:
  fixes xs :: "('a set × 'b) list"
  shows "(i<length (map fst xs). map fst xs ! i) =
    (xset xs. fst x)"
  by (auto simp add: set_conv_nth)

lemma indexed_image_union_pairs:
  fixes xs :: "('a set × ('a  'b)) list"
  shows "(i<length (map fst xs). map snd xs ! i ` (map fst xs ! i)) =
    (xset xs. snd x ` fst x)"
  by (auto simp add: set_conv_nth)

lemma pairwise_disjoint_map_fstI:
  fixes xs :: "('a set × 'b) list"
  assumes distinct: "distinct xs"
    and disj: "x y. x  set xs; y  set xs; x  y
       fst x  fst y = {}"
  shows "pairwise_disjoint (map fst xs)"
  unfolding pairwise_disjoint_def
proof (intro allI impI)
  fix i j
  assume i: "i < length (map fst xs)" and j: "j < length (map fst xs)" and ij: "i  j"
  have xi: "xs ! i  set xs" and xj: "xs ! j  set xs"
    using i j by auto
  have neq: "xs ! i  xs ! j"
    using distinct i j ij by (simp add: nth_eq_iff_index_eq)
  show "map fst xs ! i  map fst xs ! j = {}"
    using disj[OF xi xj neq] i j by simp
qed

lemma pairwise_disjoint_appendI:
  assumes xs: "pairwise_disjoint xs"
    and ys: "pairwise_disjoint ys"
    and cross: "x y. x  set xs; y  set ys  x  y = {}"
  shows "pairwise_disjoint (xs @ ys)"
  unfolding pairwise_disjoint_def
proof (intro allI impI)
  fix i j
  assume i: "i < length (xs @ ys)" and j: "j < length (xs @ ys)" and ij: "i  j"
  show "(xs @ ys) ! i  (xs @ ys) ! j = {}"
  proof (cases "i < length xs")
    case True
    show ?thesis
    proof (cases "j < length xs")
      case True
      have "xs ! i  xs ! j = {}"
        by (rule pairwise_disjoint_nthD[OF xs i < length xs True ij])
      with i < length xs True show ?thesis
        by (simp add: nth_append)
    next
      case False
      hence "(xs @ ys) ! j  set ys"
        using j by (simp add: nth_append)
      moreover have "(xs @ ys) ! i  set xs"
        by (simp add: True nth_append_left)
      ultimately show ?thesis
        using cross by simp
    qed
  next
    case False
    show ?thesis
    proof (cases "j < length xs")
      case True
      hence "(xs @ ys) ! j  set xs"
      proof -
        have "(xs @ ys) ! j = xs ! j"
          using True by (simp add: nth_append)
        moreover have "xs ! j  set xs"
          by (rule nth_mem[OF True])
        ultimately show ?thesis
          by simp
      qed
      moreover have "(xs @ ys) ! i  set ys"
        using False i by (simp add: nth_append)
      ultimately have "(xs @ ys) ! j  (xs @ ys) ! i = {}"
        using cross by blast
      thus ?thesis
        by (simp add: Int_commute)
    next
      case False
      have "ys ! (i - length xs)  ys ! (j - length xs) = {}"
        by (rule pairwise_disjoint_nthD[OF ys]) (use False ¬ i < length xs i j ij in auto)
      with False ¬ i < length xs i j show ?thesis
        by (simp add: nth_append)
    qed
  qed
qed

lemma pairwise_disjoint_appendD1:
  assumes "pairwise_disjoint (xs @ ys)"
  shows "pairwise_disjoint xs"
  unfolding pairwise_disjoint_def
proof (intro allI impI)
  fix i j
  assume i: "i < length xs" and j: "j < length xs" and ij: "i  j"
  have "(xs @ ys) ! i  (xs @ ys) ! j = {}"
    by (rule pairwise_disjoint_nthD[OF assms]) (use i j ij in simp_all)
  thus "xs ! i  xs ! j = {}"
    using i j by (simp add: nth_append)
qed

lemma pairwise_disjoint_appendD2:
  assumes "pairwise_disjoint (xs @ ys)"
  shows "pairwise_disjoint ys"
  unfolding pairwise_disjoint_def
proof (intro allI impI)
  fix i j
  assume i: "i < length ys" and j: "j < length ys" and ij: "i  j"
  have "length xs + i < length (xs @ ys)" and "length xs + j < length (xs @ ys)"
    using i j by simp_all
  moreover have "length xs + i  length xs + j"
    using ij by simp
  ultimately have "(xs @ ys) ! (length xs + i)  (xs @ ys) ! (length xs + j) = {}"
    by (rule pairwise_disjoint_nthD[OF assms])
  thus "ys ! i  ys ! j = {}"
    using i j by simp
qed

lemma pairwise_disjoint_append_crossD:
  assumes "pairwise_disjoint (xs @ ys)"
    and "i < length xs" and "j < length ys"
  shows "xs ! i  ys ! j = {}"
proof -
  have "i < length (xs @ ys)" and "length xs + j < length (xs @ ys)"
    using assms by simp_all
  moreover have "i  length xs + j"
    using assms(2) by simp
  ultimately have "(xs @ ys) ! i  (xs @ ys) ! (length xs + j) = {}"
    by (rule pairwise_disjoint_nthD[OF assms(1)])
  moreover have "(xs @ ys) ! i = xs ! i"
    using assms(2) by (simp add: nth_append)
  moreover have "(xs @ ys) ! (length xs + j) = ys ! j"
    using assms(3) by (simp add: nth_append)
  ultimately show ?thesis
    by simp
qed

lemma pairwise_disjoint_pair_imagesI:
  fixes xs :: "('a set × ('a  'b)) list"
  assumes distinct: "distinct xs"
    and disj: "x y. x  set xs; y  set xs; x  y
       snd x ` fst x  snd y ` fst y = {}"
  shows "pairwise_disjoint (map2 (λg A. g ` A) (map snd xs) (map fst xs))"
proof -
  have map_eq: "map2 (λg A. g ` A) (map snd xs) (map fst xs) =
      map (λx. snd x ` fst x) xs"
    by (induction xs) simp_all
  show ?thesis
    unfolding map_eq pairwise_disjoint_def
  proof (intro allI impI)
    fix i j
    assume i: "i < length (map (λx. snd x ` fst x) xs)"
      and j: "j < length (map (λx. snd x ` fst x) xs)" and ij: "i  j"
    have xi: "xs ! i  set xs" and xj: "xs ! j  set xs"
      using i j by auto
    have neq: "xs ! i  xs ! j"
      using distinct i j ij by (simp add: nth_eq_iff_index_eq)
    show "map (λx. snd x ` fst x) xs ! i 
        map (λx. snd x ` fst x) xs ! j = {}"
      using disj[OF xi xj neq] i j by simp
  qed
qed


section ‹Transporting finite partitions›

definition transfer_piece ::
  "'a set list  ('a  'a) list  'a set list 
    ('a  'a) list  'a set list  nat  nat  nat  'a set"
where
  "transfer_piece A e P g B k i l =
    {x  A ! k. (e ! k) x  P ! i  (g ! i) ((e ! k) x)  B ! l}"

definition transfer_map ::
  "('a  'a) list  ('a  'a) list 
    ('a  'a) list  nat  nat  nat  ('a  'a)"
where
  "transfer_map t g e k i l = (t ! l)  (g ! i)  (e ! k)"

definition transfer_pairs ::
  "'a set list  ('a  'a) list  'a set list 
    ('a  'a) list  'a set list  ('a  'a) list 
    ('a set × ('a  'a)) set"
where
  "transfer_pairs A e P g B t =
    {(transfer_piece A e P g B k i l, transfer_map t g e k i l) |
       k i l. k < length A  i < length P  l < length B}"

lemma finite_transfer_pairs [simp]: "finite (transfer_pairs A e P g B t)"
proof -
  have "transfer_pairs A e P g B t 
      (λ((k, i), l). (transfer_piece A e P g B k i l, transfer_map t g e k i l)) `
        (({..<length A} × {..<length P}) × {..<length B})"
  proof
    fix p
    assume "p  transfer_pairs A e P g B t"
    then obtain k i l where k: "k < length A" and i: "i < length P" and l: "l < length B"
      and p_eq: "p = (transfer_piece A e P g B k i l, transfer_map t g e k i l)"
      unfolding transfer_pairs_def by blast
    have tril_in: "((k, i), l)  ({..<length A} × {..<length P}) × {..<length B}"
      using k i l by simp
    show "p 
      (λ((k, i), l). (transfer_piece A e P g B k i l, transfer_map t g e k i l)) `
        (({..<length A} × {..<length P}) × {..<length B})"
      using p_eq tril_in by force
  qed
  thus ?thesis
    by (rule finite_subset) simp
qed

lemma transfer_source_cover:
  assumes A_cover: "Y = (k<length A. A ! k)"
    and B_cover: "X = (k<length B. B ! k)"
    and e_into_B: "k x. k < length A; x  A ! k  (e ! k) x  B ! k"
    and len_AB: "length A = length B"
    and source_cover: "X = (i<length P. P ! i)  (j<length Q. Q ! j)"
    and imageP_cover: "X = (i<length P. gP ! i ` (P ! i))"
    and imageQ_cover: "X = (j<length Q. gQ ! j ` (Q ! j))"
  shows "Y =
    (ptransfer_pairs A e P gP B t. fst p) 
    (qtransfer_pairs A e Q gQ B t. fst q)"
proof
  show "Y 
      (ptransfer_pairs A e P gP B t. fst p) 
      (qtransfer_pairs A e Q gQ B t. fst q)"
  proof
    fix x
    assume xY: "x  Y"
    then obtain k where k: "k < length A" and xA: "x  A ! k"
      using A_cover by blast
    have ex: "(e ! k) x  X"
      using B_cover e_into_B k len_AB xA by auto
    from source_cover ex have ex_cases:
      "(e ! k) x  (i<length P. P ! i) 
       (e ! k) x  (j<length Q. Q ! j)"
      by blast
    thus "x 
        (ptransfer_pairs A e P gP B t. fst p) 
        (qtransfer_pairs A e Q gQ B t. fst q)"
    proof
      assume "(e ! k) x  (i<length P. P ! i)"
      then obtain i where i: "i < length P" and xP: "(e ! k) x  P ! i"
        by blast
      have gxX: "(gP ! i) ((e ! k) x)  X"
        using imageP_cover i xP by blast
      then obtain l where l: "l < length B" and gxB: "(gP ! i) ((e ! k) x)  B ! l"
        using B_cover by blast
      have pair_in: "(transfer_piece A e P gP B k i l, transfer_map t gP e k i l)
           transfer_pairs A e P gP B t"
        using k i l unfolding transfer_pairs_def by blast
      have x_piece: "x  transfer_piece A e P gP B k i l"
        using xA xP gxB by (simp add: transfer_piece_def)
      have set_in: "fst (transfer_piece A e P gP B k i l, transfer_map t gP e k i l) 
          ((λp. fst p) ` transfer_pairs A e P gP B t)"
        by (rule imageI[OF pair_in])
      have x_fst: "x  fst (transfer_piece A e P gP B k i l, transfer_map t gP e k i l)"
        using x_piece by simp
      have "x   ((λp. fst p) ` transfer_pairs A e P gP B t)"
        using set_in x_fst by (rule UnionI)
      thus ?thesis
        by simp
    next
      assume "(e ! k) x  (j<length Q. Q ! j)"
      then obtain j where j: "j < length Q" and xQ: "(e ! k) x  Q ! j"
        by blast
      have gxX: "(gQ ! j) ((e ! k) x)  X"
        using imageQ_cover j xQ by blast
      then obtain l where l: "l < length B" and gxB: "(gQ ! j) ((e ! k) x)  B ! l"
        using B_cover by blast
      have pair_in: "(transfer_piece A e Q gQ B k j l, transfer_map t gQ e k j l)
           transfer_pairs A e Q gQ B t"
        using k j l unfolding transfer_pairs_def by blast
      have x_piece: "x  transfer_piece A e Q gQ B k j l"
        using xA xQ gxB by (simp add: transfer_piece_def)
      have set_in: "fst (transfer_piece A e Q gQ B k j l, transfer_map t gQ e k j l) 
          ((λq. fst q) ` transfer_pairs A e Q gQ B t)"
        by (rule imageI[OF pair_in])
      have x_fst: "x  fst (transfer_piece A e Q gQ B k j l, transfer_map t gQ e k j l)"
        using x_piece by simp
      have "x   ((λq. fst q) ` transfer_pairs A e Q gQ B t)"
        using set_in x_fst by (rule UnionI)
      thus ?thesis
        by simp
    qed
  qed
  show "(ptransfer_pairs A e P gP B t. fst p) 
      (qtransfer_pairs A e Q gQ B t. fst q)  Y"
    using A_cover unfolding transfer_pairs_def transfer_piece_def by auto
qed

lemma transfer_image_cover:
  assumes A_cover: "Y = (k<length A. A ! k)"
    and B_cover: "X = (k<length B. B ! k)"
    and len_AB: "length A = length B"
    and e_left: "k x. k < length A; x  A ! k
       (e ! k) x  B ! k  (t ! k) ((e ! k) x) = x"
    and t_left: "k y. k < length B; y  B ! k
       (t ! k) y  A ! k  (e ! k) ((t ! k) y) = y"
    and P_sub: "i. i < length P  P ! i  X"
    and image_cover: "X = (i<length P. g ! i ` (P ! i))"
  shows "Y = (ptransfer_pairs A e P g B t. snd p ` fst p)"
proof
  show "Y  (ptransfer_pairs A e P g B t. snd p ` fst p)"
  proof
    fix y
    assume yY: "y  Y"
    then obtain l where l: "l < length A" and yA: "y  A ! l"
      using A_cover by blast
    have eyB: "(e ! l) y  B ! l" and tey: "(t ! l) ((e ! l) y) = y"
      using e_left[OF l yA] by auto
    have eyX: "(e ! l) y  X"
      using B_cover eyB l len_AB by auto
    then obtain i x where i: "i < length P" and xP: "x  P ! i"
      and ey_eq: "(e ! l) y = (g ! i) x"
      using image_cover by blast
    have lB: "l < length B"
      using l len_AB by simp
    have xX: "x  X"
      using P_sub[OF i] xP by (rule subsetD)
    then obtain k where k: "k < length B" and xB: "x  B ! k"
      using B_cover by blast
    have txA: "(t ! k) x  A ! k" and etx: "(e ! k) ((t ! k) x) = x"
      using t_left[OF k xB] by auto
    have kA: "k < length A"
      using k len_AB by simp
    have piece_in: "(t ! k) x  transfer_piece A e P g B k i l"
      using txA etx xP eyB ey_eq by (simp add: transfer_piece_def)
    have pair_in: "(transfer_piece A e P g B k i l, transfer_map t g e k i l)
         transfer_pairs A e P g B t"
      using kA i lB unfolding transfer_pairs_def by blast
    have "transfer_map t g e k i l ((t ! k) x) = y"
      using etx ey_eq tey by (simp add: transfer_map_def)
    thus "y  (ptransfer_pairs A e P g B t. snd p ` fst p)"
      using pair_in piece_in by force
  qed
  show "(ptransfer_pairs A e P g B t. snd p ` fst p)  Y"
  proof
    fix y
    assume "y  (ptransfer_pairs A e P g B t. snd p ` fst p)"
    then obtain k i l x where k: "k < length A" and i: "i < length P"
      and l: "l < length B" and x_piece: "x  transfer_piece A e P g B k i l"
      and y_eq: "y = transfer_map t g e k i l x"
      unfolding transfer_pairs_def by auto
    have gxB: "(g ! i) ((e ! k) x)  B ! l"
      using x_piece by (simp add: transfer_piece_def)
    have tyA: "(t ! l) ((g ! i) ((e ! k) x))  A ! l"
      using t_left[OF l gxB] by auto
    hence "y  A ! l"
      using y_eq by (simp add: transfer_map_def)
    moreover have "A ! l  Y"
      using A_cover l len_AB by auto
    ultimately show "y  Y"
      by blast
  qed
qed

lemma transfer_source_disjoint_same:
  assumes A_disj: "pairwise_disjoint A"
    and P_disj: "pairwise_disjoint P"
    and B_disj: "pairwise_disjoint B"
    and x_in: "x  transfer_pairs A e P g B t"
    and y_in: "y  transfer_pairs A e P g B t"
    and xy: "x  y"
  shows "fst x  fst y = {}"
proof (rule ccontr)
  assume nonempty: "fst x  fst y  {}"
  obtain k i l where k: "k < length A" and i: "i < length P" and l: "l < length B"
    and x_eq: "x = (transfer_piece A e P g B k i l, transfer_map t g e k i l)"
    using x_in unfolding transfer_pairs_def by blast
  obtain k' i' l' where k': "k' < length A" and i': "i' < length P" and l': "l' < length B"
    and y_eq: "y = (transfer_piece A e P g B k' i' l', transfer_map t g e k' i' l')"
    using y_in unfolding transfer_pairs_def by blast
  from nonempty obtain z where zx: "z  fst x" and zy: "z  fst y"
    by blast
  have zA: "z  A ! k" and zeP: "(e ! k) z  P ! i"
    and zgB: "(g ! i) ((e ! k) z)  B ! l"
    using zx x_eq by (auto simp: transfer_piece_def)
  have zA': "z  A ! k'" and zeP': "(e ! k') z  P ! i'"
    and zgB': "(g ! i') ((e ! k') z)  B ! l'"
    using zy y_eq by (auto simp: transfer_piece_def)
  show False
  proof (cases "k = k'")
    case False
    have "A ! k  A ! k' = {}"
      by (rule pairwise_disjoint_nthD[OF A_disj k k' False])
    with zA zA' show False
      by blast
  next
    case k_eq: True
    show False
    proof (cases "i = i'")
      case False
      have "P ! i  P ! i' = {}"
        by (rule pairwise_disjoint_nthD[OF P_disj i i' False])
      moreover have "(e ! k) z  P ! i'"
        using zeP' k_eq by simp
      ultimately show False
        using zeP by blast
    next
      case i_eq: True
      show False
      proof (cases "l = l'")
        case False
        have "B ! l  B ! l' = {}"
          by (rule pairwise_disjoint_nthD[OF B_disj l l' False])
        moreover have "(g ! i) ((e ! k) z)  B ! l'"
          using zgB' k_eq i_eq by simp
        ultimately show False
          using zgB by blast
      next
        case l_eq: True
        have "x = y"
          using x_eq y_eq k_eq i_eq l_eq by simp
        with xy show False
          by contradiction
      qed
    qed
  qed
qed

lemma transfer_source_disjoint_cross:
  assumes A_disj: "pairwise_disjoint A"
    and PQ_cross: "i j. i < length P; j < length Q  P ! i  Q ! j = {}"
    and B_disj: "pairwise_disjoint B"
    and x_in: "x  transfer_pairs A e P gP B t"
    and y_in: "y  transfer_pairs A e Q gQ B t"
  shows "fst x  fst y = {}"
proof (rule ccontr)
  assume nonempty: "fst x  fst y  {}"
  obtain k i l where k: "k < length A" and i: "i < length P" and l: "l < length B"
    and x_eq: "x = (transfer_piece A e P gP B k i l, transfer_map t gP e k i l)"
    using x_in unfolding transfer_pairs_def by blast
  obtain k' j l' where k': "k' < length A" and j: "j < length Q" and l': "l' < length B"
    and y_eq: "y = (transfer_piece A e Q gQ B k' j l', transfer_map t gQ e k' j l')"
    using y_in unfolding transfer_pairs_def by blast
  from nonempty obtain z where zx: "z  fst x" and zy: "z  fst y"
    by blast
  have zA: "z  A ! k" and zeP: "(e ! k) z  P ! i"
    using zx x_eq by (auto simp: transfer_piece_def)
  have zA': "z  A ! k'" and zeQ: "(e ! k') z  Q ! j"
    using zy y_eq by (auto simp: transfer_piece_def)
  show False
  proof (cases "k = k'")
    case False
    have "A ! k  A ! k' = {}"
      by (rule pairwise_disjoint_nthD[OF A_disj k k' False])
    with zA zA' show False
      by blast
  next
    case k_eq: True
    have "P ! i  Q ! j = {}"
      by (rule PQ_cross[OF i j])
    moreover have "(e ! k) z  Q ! j"
      using zeQ k_eq by simp
    ultimately show False
      using zeP by blast
  qed
qed

lemma transfer_image_disjoint_same:
  assumes len_AB: "length A = length B"
    and A_disj: "pairwise_disjoint A"
    and B_disj: "pairwise_disjoint B"
    and image_disj: "pairwise_disjoint (map2 (λh C. h ` C) g P)"
    and len: "length P = length g"
    and g_inj: "i. i < length P  inj (g ! i)"
    and e_into_B: "k x. k < length A; x  A ! k  (e ! k) x  B ! k"
    and t_left: "l y. l < length B; y  B ! l
       (t ! l) y  A ! l  (e ! l) ((t ! l) y) = y"
    and x_in: "x  transfer_pairs A e P g B t"
    and y_in: "y  transfer_pairs A e P g B t"
    and xy: "x  y"
  shows "snd x ` fst x  snd y ` fst y = {}"
proof (rule ccontr)
  assume nonempty: "snd x ` fst x  snd y ` fst y  {}"
  obtain k i l where k: "k < length A" and i: "i < length P" and l: "l < length B"
    and x_eq: "x = (transfer_piece A e P g B k i l, transfer_map t g e k i l)"
    using x_in unfolding transfer_pairs_def by blast
  obtain k' i' l' where k': "k' < length A" and i': "i' < length P" and l': "l' < length B"
    and y_eq: "y = (transfer_piece A e P g B k' i' l', transfer_map t g e k' i' l')"
    using y_in unfolding transfer_pairs_def by blast
  from nonempty obtain z where zx: "z  snd x ` fst x" and zy: "z  snd y ` fst y"
    by blast
  then obtain a b where
      a_piece: "a  transfer_piece A e P g B k i l"
    and z_a: "z = transfer_map t g e k i l a"
    and b_piece: "b  transfer_piece A e P g B k' i' l'"
    and z_b: "z = transfer_map t g e k' i' l' b"
    using x_eq y_eq by auto
  have aA: "a  A ! k" and aeP: "(e ! k) a  P ! i"
    and gaB: "(g ! i) ((e ! k) a)  B ! l"
    using a_piece by (auto simp: transfer_piece_def)
  have bA: "b  A ! k'" and beP: "(e ! k') b  P ! i'"
    and gbB: "(g ! i') ((e ! k') b)  B ! l'"
    using b_piece by (auto simp: transfer_piece_def)
  have lA: "l < length A" and lA': "l' < length A"
    using l l' len_AB by simp_all
  have zA_l: "z  A ! l"
    using t_left[OF l gaB] z_a by (simp add: transfer_map_def)
  have zA_l': "z  A ! l'"
    using t_left[OF l' gbB] z_b by (simp add: transfer_map_def)
  show False
  proof (cases "l = l'")
    case False
    have "A ! l  A ! l' = {}"
      by (rule pairwise_disjoint_nthD[OF A_disj lA lA' False])
    with zA_l zA_l' show False
      by blast
  next
    case l_eq: True
    have ez_a: "(e ! l) z = (g ! i) ((e ! k) a)"
      using t_left[OF l gaB] z_a by (simp add: transfer_map_def)
    have ez_b: "(e ! l) z = (g ! i') ((e ! k') b)"
      using t_left[OF l' gbB] z_b l_eq by (simp add: transfer_map_def)
    have g_eq: "(g ! i) ((e ! k) a) = (g ! i') ((e ! k') b)"
      using ez_a ez_b by simp
    show False
    proof (cases "i = i'")
      case False then 
      have img_i: "(g ! i) ((e ! k) a)  map2 (λh C. h ` C) g P ! i"
        using aeP i len by simp
      have img_i': "(g ! i') ((e ! k') b)  map2 (λh C. h ` C) g P ! i'"
        using beP i' len by simp
      have "map2 (λh C. h ` C) g P ! i 
          map2 (λh C. h ` C) g P ! i' = {}"
        by (rule pairwise_disjoint_nthD[OF image_disj]) (use i i' False len in simp_all)
      moreover have "(g ! i) ((e ! k) a)  map2 (λh C. h ` C) g P ! i'"
        using img_i' g_eq by simp
      ultimately show False
        using img_i by auto
    next
      case i_eq: True
      have e_eq: "(e ! k) a = (e ! k') b"
        using g_eq i_eq g_inj[OF i] by (auto dest: injD)
      show False
      proof (cases "k = k'")
        case False
        have kB: "k < length B" and kB': "k' < length B"
          using k k' len_AB by simp_all
        have eaB: "(e ! k) a  B ! k"
          by (rule e_into_B[OF k aA])
        have ebB: "(e ! k') b  B ! k'"
          by (rule e_into_B[OF k' bA])
        have "B ! k  B ! k' = {}"
          by (rule pairwise_disjoint_nthD[OF B_disj kB kB' False])
        moreover have "(e ! k) a  B ! k'"
          using ebB e_eq by simp
        ultimately show False
          using eaB by auto
      next
        case k_eq: True
        have "x = y"
          using x_eq y_eq k_eq i_eq l_eq by simp
        with xy show False
          by contradiction
      qed
    qed
  qed
qed

lemma transfer_partitioned_paradox:
  assumes len_AB: "length A = length B"
    and A_cover: "Y = (k<length A. A ! k)"
    and A_disj: "pairwise_disjoint A"
    and B_cover: "X = (k<length B. B ! k)"
    and B_disj: "pairwise_disjoint B"
    and e_left: "k x. k < length A; x  A ! k
       (e ! k) x  B ! k  (t ! k) ((e ! k) x) = x"
    and t_left: "k y. k < length B; y  B ! k
       (t ! k) y  A ! k  (e ! k) ((t ! k) y) = y"
    and lenP: "length P = length gP"
    and lenQ: "length Q = length gQ"
    and source_disj: "pairwise_disjoint (P @ Q)"
    and source_cover: "X = (i<length P. P ! i)  (j<length Q. Q ! j)"
    and imageP_disj: "pairwise_disjoint (map2 (λh C. h ` C) gP P)"
    and imageQ_disj: "pairwise_disjoint (map2 (λh C. h ` C) gQ Q)"
    and imageP_cover: "X = (i<length P. gP ! i ` (P ! i))"
    and imageQ_cover: "X = (j<length Q. gQ ! j ` (Q ! j))"
    and gP_inj: "i. i < length P  inj (gP ! i)"
    and gQ_inj: "j. j < length Q  inj (gQ ! j)"
    and mapsP: "k i l. k < length A; i < length P; l < length B
       transfer_map t gP e k i l  M"
    and mapsQ: "k j l. k < length A; j < length Q; l < length B
       transfer_map t gQ e k j l  M"
  shows "P' Q' :: 'a set list. gP' gQ' :: ('a  'a) list.
      length P' = length gP'  length Q' = length gQ' 
      set gP'  M  set gQ'  M 
      pairwise_disjoint (P' @ Q') 
      pairwise_disjoint (map2 (λh C. h ` C) gP' P') 
      pairwise_disjoint (map2 (λh C. h ` C) gQ' Q') 
      Y = (i<length P'. P' ! i)  (j<length Q'. Q' ! j) 
      Y = (i<length P'. gP' ! i ` (P' ! i)) 
      Y = (j<length Q'. gQ' ! j ` (Q' ! j))"
proof -
  let ?CP = "transfer_pairs A e P gP B t"
  let ?CQ = "transfer_pairs A e Q gQ B t"
  have finite_CP: "finite ?CP"
    by simp
  have finite_CQ: "finite ?CQ"
    by simp
  obtain pairsP where setP: "set pairsP = ?CP" and distinctP: "distinct pairsP"
    using finite_distinct_list[OF finite_CP] by blast
  obtain pairsQ where setQ: "set pairsQ = ?CQ" and distinctQ: "distinct pairsQ"
    using finite_distinct_list[OF finite_CQ] by blast
  let ?P' = "map fst pairsP"
  let ?Q' = "map fst pairsQ"
  let ?gP' = "map snd pairsP"
  let ?gQ' = "map snd pairsQ"

  have P_disj: "pairwise_disjoint P"
    by (rule pairwise_disjoint_appendD1[OF source_disj])
  have Q_disj: "pairwise_disjoint Q"
    by (rule pairwise_disjoint_appendD2[OF source_disj])
  have PQ_cross: "i j. i < length P; j < length Q  P ! i  Q ! j = {}"
    by (rule pairwise_disjoint_append_crossD[OF source_disj])

  have P'_disj: "pairwise_disjoint ?P'"
  proof (rule pairwise_disjoint_map_fstI[OF distinctP])
    fix x y
    assume "x  set pairsP" "y  set pairsP" "x  y"
    thus "fst x  fst y = {}"
      using setP transfer_source_disjoint_same[OF A_disj P_disj B_disj] by blast
  qed
  have Q'_disj: "pairwise_disjoint ?Q'"
    by (metis A_disj B_disj Q_disj distinctQ pairwise_disjoint_map_fstI setQ transfer_source_disjoint_same)
  have cross_disj: "x y. x  set ?P'; y  set ?Q'  x  y = {}"
  proof -
    fix x y
    assume x: "x  set ?P'" and y: "y  set ?Q'"
    then obtain px qy where px: "px  set pairsP" and qy: "qy  set pairsQ"
      and x_eq: "x = fst px" and y_eq: "y = fst qy"
      by auto
    show "x  y = {}"
      using transfer_source_disjoint_cross[OF A_disj PQ_cross B_disj]
        setP setQ px qy x_eq y_eq by blast
  qed
  have source_disj': "pairwise_disjoint (?P' @ ?Q')"
    by (rule pairwise_disjoint_appendI[OF P'_disj Q'_disj cross_disj])

  have imageP_disj': "pairwise_disjoint (map2 (λh C. h ` C) ?gP' ?P')"
  proof (rule pairwise_disjoint_pair_imagesI[OF distinctP])
    fix x y
    assume "x  set pairsP" "y  set pairsP" "x  y"
    thus "snd x ` fst x  snd y ` fst y = {}"
      using setP transfer_image_disjoint_same[
        OF len_AB A_disj B_disj imageP_disj lenP gP_inj _ t_left]
        e_left by blast
  qed
  have imageQ_disj': "pairwise_disjoint (map2 (λh C. h ` C) ?gQ' ?Q')"
  proof (rule pairwise_disjoint_pair_imagesI[OF distinctQ])
    fix x y
    assume "x  set pairsQ" "y  set pairsQ" "x  y"
    thus "snd x ` fst x  snd y ` fst y = {}"
      using setQ transfer_image_disjoint_same[
        OF len_AB A_disj B_disj imageQ_disj lenQ gQ_inj _ t_left]
        e_left by blast
  qed

  have P_sub: "i. i < length P  P ! i  X"
    using source_cover by blast
  have Q_sub: "j. j < length Q  Q ! j  X"
    using source_cover by blast

  have source_cover': "Y = (i<length ?P'. ?P' ! i)  (j<length ?Q'. ?Q' ! j)"
  proof -
    have "Y = (p?CP. fst p)  (q?CQ. fst q)"
      by (rule transfer_source_cover[OF A_cover B_cover _ len_AB source_cover imageP_cover imageQ_cover])
        (use e_left in auto)
    also have " = (i<length ?P'. ?P' ! i)  (j<length ?Q'. ?Q' ! j)"
      using setP setQ indexed_union_map_fst[of pairsP] indexed_union_map_fst[of pairsQ]
      by simp
    finally show ?thesis .
  qed
  have imageP_cover': "Y = (i<length ?P'. ?gP' ! i ` (?P' ! i))"
  proof -
    have "Y = (p?CP. snd p ` fst p)"
      by (rule transfer_image_cover[OF A_cover B_cover len_AB e_left t_left P_sub imageP_cover])
    also have " = (i<length ?P'. ?gP' ! i ` (?P' ! i))"
      using setP indexed_image_union_pairs[of pairsP] by simp
    finally show ?thesis .
  qed
  have imageQ_cover': "Y = (j<length ?Q'. ?gQ' ! j ` (?Q' ! j))"
  proof -
    have "Y = (q?CQ. snd q ` fst q)"
      by (rule transfer_image_cover[OF A_cover B_cover len_AB e_left t_left Q_sub imageQ_cover])
    also have " = (j<length ?Q'. ?gQ' ! j ` (?Q' ! j))"
      using setQ indexed_image_union_pairs[of pairsQ] by simp
    finally show ?thesis .
  qed

  have mapsP': "set ?gP'  M"
    using setP mapsP unfolding transfer_pairs_def by auto
  have mapsQ': "set ?gQ'  M"
    using setQ mapsQ unfolding transfer_pairs_def by auto

  show ?thesis
  proof (intro exI conjI)
    show "length ?P' = length ?gP'"
      by simp
    show "length ?Q' = length ?gQ'"
      by simp
    show "set ?gP'  M"
      by (rule mapsP')
    show "set ?gQ'  M"
      by (rule mapsQ')
    show "pairwise_disjoint (?P' @ ?Q')"
      by (rule source_disj')
    show "pairwise_disjoint (map2 (λh C. h ` C) ?gP' ?P')"
      by (rule imageP_disj')
    show "pairwise_disjoint (map2 (λh C. h ` C) ?gQ' ?Q')"
      by (rule imageQ_disj')
    show "Y = (i<length ?P'. ?P' ! i)  (j<length ?Q'. ?Q' ! j)"
      by (rule source_cover')
    show "Y = (i<length ?P'. ?gP' ! i ` (?P' ! i))"
      by (rule imageP_cover')
    show "Y = (j<length ?Q'. ?gQ' ! j ` (?Q' ! j))"
      by (rule imageQ_cover')
  qed
qed

end