Theory Vosper_Support

theory Vosper_Support
  imports Cauchy_Davenport_Prime_Field
begin

section ‹Arithmetic progressions in prime fields›

text ‹
  Vosper's theorem is formulated in terms of arithmetic progressions with a
  shared common difference. This theory isolates the corresponding progression
  notation, translation lemmas, and the overlap criterion that recovers a
  progression from near-invariance under translation.
›

subsection ‹Basic progression infrastructure›

definition ap_segment :: "'a::semiring_1  'a  nat  'a set" where
  "ap_segment a d n = (λi. a + of_nat i * d) ` {..<n}"

definition arithmetic_progression :: "'a::semiring_1 set  bool" where
  "arithmetic_progression A  (a d n. A = ap_segment a d n)"

lemma arithmetic_progressionI:
  "A = ap_segment a d n  arithmetic_progression A"
  unfolding arithmetic_progression_def by blast

lemma arithmetic_progressionE:
  assumes "arithmetic_progression A"
  obtains a d n where "A = ap_segment a d n"
  using assms by (auto simp: arithmetic_progression_def)

lemma finite_ap_segment [simp]:
  "finite (ap_segment a d n)"
  by (simp add: ap_segment_def)

lemma ap_segment_empty [simp]:
  "ap_segment a d 0 = {}"
  by (simp add: ap_segment_def)

lemma ap_segment_zero_step:
  fixes a :: "'a::semiring_1"
  assumes "0 < n"
  shows "ap_segment a 0 n = {a}"
proof
  show "ap_segment a 0 n  {a}"
    by (auto simp: ap_segment_def)
next
  have "a + of_nat 0 * 0  ap_segment a 0 n"
    using assms by (auto simp: ap_segment_def)
  then show "{a}  ap_segment a 0 n"
    by simp
qed

lemma ap_segment_translate:
  fixes a d c :: "'a::semiring_1"
  shows "translate c (ap_segment a d n) = ap_segment (c + a) d n"
proof
  show "translate c (ap_segment a d n)  ap_segment (c + a) d n"
    by (auto simp: translate_def ap_segment_def ac_simps)
next
  show "ap_segment (c + a) d n  translate c (ap_segment a d n)"
  proof
    fix x
    assume "x  ap_segment (c + a) d n"
    then obtain i where i_lt: "i < n" and x: "x = (c + a) + of_nat i * d"
      by (auto simp: ap_segment_def)
    have "a + of_nat i * d  ap_segment a d n"
      using i_lt by (auto simp: ap_segment_def)
    moreover have "x = c + (a + of_nat i * d)"
      using x by (simp add: ac_simps)
    ultimately show "x  translate c (ap_segment a d n)"
      by (auto simp: translate_def)
  qed
qed

lemma arithmetic_progression_translate [simp]:
  fixes c :: "'a::ring_1"
  shows "arithmetic_progression (translate c A)  arithmetic_progression A"
proof
  assume "arithmetic_progression (translate c A)"
  then obtain a d n where eq: "translate c A = ap_segment a d n"
    unfolding arithmetic_progression_def by blast
  have "A = translate (- c) (translate c A)"
  proof
    show "A  translate (- c) (translate c A)"
    proof
      fix x
      assume "x  A"
      then have cx_in: "c + x  translate c A"
        by (auto simp: translate_def)
      have x_eq: "x = - c + (c + x)"
        by simp
      show "x  translate (- c) (translate c A)"
      proof (unfold translate_def, rule image_eqI[where x = "c + x"])
        show "c + x  (+) c ` A"
          using cx_in unfolding translate_def by simp
        show "x = - c + (c + x)"
          using x_eq by simp
      qed
    qed
  next
    show "translate (- c) (translate c A)  A"
    proof
      fix x
      assume "x  translate (- c) (translate c A)"
      then obtain y where y_in: "y  translate c A" and x: "x = - c + y"
        by (auto simp: translate_def)
      then obtain z where z_in: "z  A" and y: "y = c + z"
        by (auto simp: translate_def)
      from x y have "x = z"
        by simp
      with z_in show "x  A"
        by simp
    qed
  qed
  also have " = ap_segment ((- c) + a) d n"
    using eq by (simp add: ap_segment_translate)
  finally show "arithmetic_progression A"
    unfolding arithmetic_progression_def by blast
next
  assume "arithmetic_progression A"
  then obtain a d n where "A = ap_segment a d n"
    unfolding arithmetic_progression_def by blast
  then show "arithmetic_progression (translate c A)"
    unfolding arithmetic_progression_def
    by (intro exI[of _ "c + a"] exI[of _ d] exI[of _ n]) (simp add: ap_segment_translate)
qed

lemma sumset_ap_segment_pair_suc:
  fixes a d :: "'a::semiring_1"
  shows "sumset (ap_segment a d (Suc n)) {0, d} = ap_segment a d (Suc (Suc n))"
proof
  show "sumset (ap_segment a d (Suc n)) {0, d}  ap_segment a d (Suc (Suc n))"
  proof
    fix x
    assume "x  sumset (ap_segment a d (Suc n)) {0, d}"
    then obtain y b where
        y_in: "y  ap_segment a d (Suc n)"
      and b_in: "b  {0, d}"
      and x_eq: "x = y + b"
      by (rule sumsetE)
    from y_in obtain i where i_lt: "i < Suc n" and y_eq: "y = a + of_nat i * d"
      by (auto simp: ap_segment_def)
    show "x  ap_segment a d (Suc (Suc n))"
    proof (cases "b = 0")
      case True
      have "i < Suc (Suc n)"
        using i_lt by simp
      with True x_eq y_eq show ?thesis
        by (auto simp: ap_segment_def)
    next
      case False
      with b_in have "b = d"
        by simp
      with x_eq y_eq have "x = a + of_nat (Suc i) * d"
        by (simp add: algebra_simps)
      moreover have "Suc i < Suc (Suc n)"
        using i_lt by simp
      ultimately show ?thesis
      proof -
        have "a + of_nat (Suc i) * d  ap_segment a d (Suc (Suc n))"
        proof (unfold ap_segment_def, rule image_eqI[where x = "Suc i"])
          show "Suc i  {..<Suc (Suc n)}"
            using i_lt by simp
          show "a + of_nat (Suc i) * d = a + of_nat (Suc i) * d"
            by simp
        qed
        then show ?thesis
          using x = a + of_nat (Suc i) * d by simp
      qed
    qed
  qed
next
  show "ap_segment a d (Suc (Suc n))  sumset (ap_segment a d (Suc n)) {0, d}"
  proof
    fix x
    assume "x  ap_segment a d (Suc (Suc n))"
    then obtain j where j_lt: "j < Suc (Suc n)" and x_eq: "x = a + of_nat j * d"
      by (auto simp: ap_segment_def)
    show "x  sumset (ap_segment a d (Suc n)) {0, d}"
    proof (cases "j < Suc n")
      case True
      have "a + of_nat j * d  ap_segment a d (Suc n)"
        using True by (auto simp: ap_segment_def)
      then have "(a + of_nat j * d) + 0  sumset (ap_segment a d (Suc n)) {0, d}"
        by (rule sumsetI) simp_all
      then show ?thesis
        using x_eq by simp
    next
      case False
      with j_lt have j_eq: "j = Suc n"
        by simp
      have "a + of_nat n * d  ap_segment a d (Suc n)"
        by (auto simp: ap_segment_def)
      moreover have "x = (a + of_nat n * d) + d"
        using x_eq j_eq by (simp add: algebra_simps)
      ultimately show ?thesis
      proof -
        have "(a + of_nat n * d) + d  sumset (ap_segment a d (Suc n)) {0, d}"
          using a + of_nat n * d  ap_segment a d (Suc n)
          by (rule sumsetI) simp_all
        then show ?thesis
          using x = (a + of_nat n * d) + d by simp
      qed
    qed
  qed
qed

lemma of_nat_eq_below_prime_card:
  fixes i j :: nat
  assumes prime_card: "prime (card (UNIV :: 'a::finite_field set))"
  assumes i_lt: "i < card (UNIV :: 'a set)"
  assumes j_lt: "j < card (UNIV :: 'a set)"
  assumes eq: "(of_nat i :: 'a) = of_nat j"
  shows "i = j"
proof (cases i j rule: linorder_cases)
  case less
  have "CHAR('a) dvd (j - i)"
    using eq less by (simp add: of_nat_eq_iff_char_dvd)
  then have card_dvd: "card (UNIV :: 'a set) dvd (j - i)"
    by (simp add: prime_card_eq_char[OF prime_card])
  have "j - i > 0"
    using less by simp
  then have "card (UNIV :: 'a set)  j - i"
    using card_dvd prime_card by (meson dvd_imp_le prime_gt_0_nat)
  moreover have "j - i < card (UNIV :: 'a set)"
    using i_lt j_lt less by simp
  ultimately show ?thesis
    by simp
next
  case greater
  have "CHAR('a) dvd (i - j)"
  proof -
    have "(of_nat j :: 'a) = of_nat i"
      using eq by simp
    with greater show ?thesis
      by (simp add: of_nat_eq_iff_char_dvd)
  qed
  then have card_dvd: "card (UNIV :: 'a set) dvd (i - j)"
    by (simp add: prime_card_eq_char[OF prime_card])
  have "i - j > 0"
    using greater by simp
  then have "card (UNIV :: 'a set)  i - j"
    using card_dvd prime_card by (meson dvd_imp_le prime_gt_0_nat)
  moreover have "i - j < card (UNIV :: 'a set)"
    using i_lt j_lt greater by simp
  ultimately show ?thesis
    by simp
qed simp

lemma inj_on_ap_segment_index:
  fixes a d :: "'a::finite_field"
  assumes prime_card: "prime (card (UNIV :: 'a::finite_field set))"
  assumes d_nonzero: "d  0"
  assumes n_le: "n  card (UNIV :: 'a set)"
  shows "inj_on (λi. a + of_nat i * d) {..<n}"
proof (rule inj_onI)
  fix i j
  assume i_in: "i  {..<n}"
  assume j_in: "j  {..<n}"
  assume eq: "a + of_nat i * d = a + of_nat j * d"
  have "(of_nat i :: 'a) = of_nat j"
  proof -
    have "((of_nat i :: 'a) - of_nat j) * d = 0"
      using eq by (simp add: algebra_simps)
    with d_nonzero have "(of_nat i :: 'a) - of_nat j = 0"
      by auto
    then show ?thesis
      by simp
  qed
  then show "i = j"
    using i_in j_in n_le prime_card by (intro of_nat_eq_below_prime_card) auto
qed

lemma card_ap_segment:
  fixes a d :: "'a::finite_field"
  assumes prime_card: "prime (card (UNIV :: 'a::finite_field set))"
  assumes d_nonzero: "d  0"
  assumes n_le: "n  card (UNIV :: 'a set)"
  shows "card (ap_segment a d n) = n"
  by (simp add: ap_segment_def card_image inj_on_ap_segment_index[OF prime_card d_nonzero n_le])

lemma arithmetic_progression_obtain_card:
  fixes A :: "'a::finite_field set"
  assumes prime_card: "prime (card (UNIV :: 'a set))"
  assumes ap: "arithmetic_progression A"
  assumes card_ge2: "2  card A"
  assumes small: "card A < card (UNIV :: 'a set)"
  obtains a d where "d  0" "A = ap_segment a d (card A)"
proof -
  obtain a d n where A_eq: "A = ap_segment a d n"
    using ap by (rule arithmetic_progressionE)
  have n_pos: "0 < n"
  proof (rule ccontr)
    assume "¬ 0 < n"
    then have "n = 0"
      by simp
    with A_eq card_ge2 show False
      by simp
  qed
  have d_nonzero: "d  0"
  proof
    assume "d = 0"
    with A_eq n_pos have "A = {a}"
      by (simp add: ap_segment_zero_step)
    with card_ge2 show False
      by simp
  qed
  let ?p = "card (UNIV :: 'a set)"
  have n_lt_p: "n < ?p"
  proof (rule ccontr)
    assume "¬ n < ?p"
    then have p_le_n: "?p  n"
      by simp
    have "ap_segment a d ?p  ap_segment a d n"
      using p_le_n by (auto simp: ap_segment_def)
    moreover have "ap_segment a d ?p = UNIV"
    proof -
      have "card (ap_segment a d ?p) = ?p"
        by (rule card_ap_segment[OF prime_card d_nonzero]) simp
      moreover have "ap_segment a d ?p  UNIV"
        by simp
      ultimately show ?thesis
        using finite_UNIV by (intro card_subset_eq) auto
    qed
    ultimately have "UNIV  A"
      using A_eq by simp
    then have "A = UNIV"
      by auto
    with small show False
      by simp
  qed
  have n_le_p: "n  ?p"
    using n_lt_p by simp
  have "card A = n"
    using A_eq card_ap_segment[OF prime_card d_nonzero n_le_p, of a] by simp
  then have "A = ap_segment a d (card A)"
    using A_eq by simp
  then show ?thesis
    using d_nonzero that by blast
qed

lemma step_image_UNIV:
  fixes a d :: "'a::finite_field"
  assumes prime_card: "prime (card (UNIV :: 'a::finite_field set))"
  assumes d_nonzero: "d  0"
  shows "(λi. a + of_nat i * d) ` {..<card (UNIV :: 'a set)} = UNIV"
proof -
  have inj: "inj_on (λi. a + of_nat i * d) {..<card (UNIV :: 'a set)}"
    by (rule inj_on_ap_segment_index[OF prime_card d_nonzero]) simp
  have "card ((λi. a + of_nat i * d) ` {..<card (UNIV :: 'a set)}) = card (UNIV :: 'a set)"
    by (simp add: card_image inj)
  moreover have "(λi. a + of_nat i * d) ` {..<card (UNIV :: 'a set)}  UNIV"
    by simp
  ultimately show ?thesis
    using finite_UNIV by (intro card_subset_eq) auto
qed

lemma predecessor_closed_initial_segment:
  fixes S :: "nat set"
  assumes fin: "finite S"
  assumes zero: "0  S"
  assumes pred: "k. Suc k  S  k  S"
  shows "S = {..<card S}"
proof
  have init: "{..<Suc k}  S" if "k  S" for k
    using that
  proof (induction k)
    case 0
    then show ?case
      by auto
  next
    case (Suc k)
    have "k  S"
      using pred Suc.prems by blast
    then have "{..<Suc k}  S"
      by (rule Suc.IH)
    show ?case
    proof
      fix x
      assume x_lt: "x  {..<Suc (Suc k)}"
      show "x  S"
      proof (cases "x = Suc k")
        case True
        with Suc.prems show ?thesis
          by simp
      next
        case False
        with x_lt have "x < Suc k"
          by simp
        with {..<Suc k}  S show ?thesis
          by auto
      qed
    qed
  qed
  show "S  {..<card S}"
  proof
    fix k
    assume "k  S"
    then have "{..<Suc k}  S"
      by (rule init)
    then have "Suc k  card S"
    proof -
      have "card {..<Suc k} = Suc k"
        by simp
      moreover have "card {..<Suc k}  card S"
        using fin {..<Suc k}  S by (intro card_mono) auto
      ultimately show ?thesis
        by simp
    qed
    then show "k  {..<card S}"
      by simp
  qed
next
  show "{..<card S}  S"
  proof
    have down: "i  S" if "i  j" "j  S" for i j
      using that
    proof (induction j arbitrary: i)
      case 0
      then show ?case
        by simp
    next
      case (Suc j)
      show ?case
      proof (cases "i = Suc j")
        case True
        with Suc.prems show ?thesis
          by simp
      next
        case False
        with Suc.prems have i_le_j: "i  j"
          by simp
        have "j  S"
          using pred Suc.prems(2) by simp
        from Suc.IH[OF i_le_j this] show ?thesis .
      qed
    qed
    fix k
    assume k_lt: "k  {..<card S}"
    show "k  S"
    proof (rule ccontr)
      assume k_notin: "k  S"
      have "S  {..<k}"
      proof
        fix j
        assume j_in: "j  S"
        show "j  {..<k}"
        proof (rule ccontr)
          assume "j  {..<k}"
          then have "k  j"
            by simp
          then have "k  S"
            using j_in by (rule down)
          with k_notin show False
            by simp
        qed
      qed
      then have "card S  k"
      proof -
        have "card S  card {..<k}"
          using fin S  {..<k} by (intro card_mono) auto
        then show ?thesis
          by simp
      qed
      with k_lt show False
        by simp
    qed
  qed
qed

subsection ‹Recovering a progression from maximal overlap›

text ‹
  The following lemmas package the structural step used repeatedly in the
  Vosper proof: if a set is almost preserved by translation with a nonzero step,
  then it must itself be an arithmetic progression with that step.
›

lemma ap_segment_from_maximal_shift_overlap:
  fixes A :: "'a::finite_field set"
  assumes prime_card: "prime (card (UNIV :: 'a set))"
  assumes d_nonzero: "d  0"
  assumes small: "card A < card (UNIV :: 'a set)"
  assumes overlap: "card (A  translate d A) = card A - 1"
  obtains a where "A = ap_segment a d (card A)"
proof (cases "A = {}")
  case True
  then show ?thesis
  proof -
    have "A = ap_segment 0 d (card A)"
      using True by simp
    then show ?thesis
      by (rule that)
  qed
next
  case False
  have finA: "finite A"
    using finite_subset[of A "UNIV :: 'a set"] by simp
  have cardA_pos: "0 < card A"
    using False finA by auto
  have one_start: "card (A - translate d A) = 1"
  proof -
    have "A  translate d A  A"
      by simp
    then have "card (A - (A  translate d A)) = card A - card (A  translate d A)"
      using finA by (simp add: card_Diff_subset)
    moreover have "A - (A  translate d A) = A - translate d A"
      by auto
    ultimately show ?thesis
      using overlap cardA_pos by simp
  qed
  then obtain a where a_start: "A - translate d A = {a}"
    by (meson card_1_singletonE)
  then have a_in: "a  A" and a_notin: "a  translate d A"
    by auto
  define p where "p = card (UNIV :: 'a set)"
  define f where "f i = a + of_nat i * d" for i
  define S where "S = {i  {..<p}. f i  A}"
  have p_pos: "0 < p"
    unfolding p_def using prime_card prime_gt_0_nat by blast
  have image_all: "f ` {..<p} = UNIV"
    unfolding p_def f_def by (rule step_image_UNIV[OF prime_card d_nonzero])
  have A_as_image: "A = f ` S"
    unfolding S_def
    using image_all by (auto simp: f_def)
  have inj_f: "inj_on f {..<p}"
    unfolding p_def f_def
    by (rule inj_on_ap_segment_index[OF prime_card d_nonzero]) simp
  have finS: "finite S"
    unfolding S_def by simp
  have cardS: "card S = card A"
  proof -
    have S_subset: "S  {..<p}"
      unfolding S_def by auto
    have inj_fS: "inj_on f S"
      using inj_f S_subset by (rule inj_on_subset)
    have "card (f ` S) = card S"
      using finS inj_fS by (simp add: card_image)
    with A_as_image show ?thesis
      by simp
  qed
  have zero_in_S: "0  S"
    using a_in p_pos by (simp add: S_def f_def)
  have pred_closed: "Suc k  S  k  S" for k
  proof -
    assume suc_in: "Suc k  S"
    then have sk_lt: "Suc k < p"
      by (simp add: S_def)
    have fk_in: "f (Suc k)  A"
      using suc_in by (simp add: S_def)
    have fk_neq_a: "f (Suc k)  a"
    proof
      assume "f (Suc k) = a"
      then have "f (Suc k) = f 0"
        by (simp add: f_def)
      have suc_mem: "Suc k  {..<p}"
        using sk_lt by simp
      have zero_mem: "0  {..<p}"
        using p_pos by simp
      from inj_f suc_mem zero_mem f (Suc k) = f 0 have "Suc k = 0"
        unfolding inj_on_def by blast
      then show False
        by simp
    qed
    have "f (Suc k)  A - translate d A  False"
      using a_start fk_neq_a by auto
    then have fk_shift: "f (Suc k)  translate d A"
      using fk_in by blast
    then obtain y where y_in: "y  A" and fy: "f (Suc k) = d + y"
      by (auto simp: translate_iff)
    have "y = f k"
      using fy by (simp add: f_def algebra_simps)
    with y_in show "k  S"
      using sk_lt by (simp add: S_def)
  qed
  have S_init: "S = {..<card S}"
    by (rule predecessor_closed_initial_segment[OF finS zero_in_S pred_closed])
  have "A = f ` {..<card A}"
    using A_as_image S_init cardS by simp
  also have " = ap_segment a d (card A)"
    by (simp add: ap_segment_def f_def)
  finally have "A = ap_segment a d (card A)" .
  then show ?thesis
    using that by blast
qed

lemma arithmetic_progression_from_maximal_shift_overlap:
  fixes A :: "'a::finite_field set"
  assumes prime_card: "prime (card (UNIV :: 'a set))"
  assumes d_nonzero: "d  0"
  assumes small: "card A < card (UNIV :: 'a set)"
  assumes overlap: "card (A  translate d A) = card A - 1"
  shows "arithmetic_progression A"
proof -
  obtain a where "A = ap_segment a d (card A)"
    by (rule ap_segment_from_maximal_shift_overlap[OF prime_card d_nonzero small overlap])
  then show ?thesis
    unfolding arithmetic_progression_def by blast
qed

end