Theory Padic_Field_Topology_Bridge

section ‹Topology, metric space, completeness for $p$-adic fields›

text ‹This additional theory links the topology of a $p$-adic field to the standard notion 
of abstract topology from the Analysis library. It also proves completeness for $p$-adic fields. 
Supplied by LCP and Claude.›

theory Padic_Field_Topology_Bridge
  imports Padic_Field_Topology "HOL-Analysis.Abstract_Metric_Spaces"

begin

context padic_fields
begin

subsection ‹The $p$-adic topology is a topology›

definition padic_topology :: "padic_number topology" where
  "padic_topology = topology is_open"

lemma istopology_padic: "istopology is_open"
  unfolding istopology_def
proof (intro conjI allI impI)
  fix S T 
  assume "is_open S" "is_open T"
  show "is_open (S  T)"
  proof (rule is_openI)
    show "S  T  carrier Qp"
      using is_open S is_open_imp_in_Qp by blast
    fix c assume "c  S  T"
    then obtain n m where "B⇘n⇙[c]  S" "B⇘m⇙[c]  T"
      using is_open S is_open T is_open_def by force
    then have "B⇘max n m⇙[c]  S  T"
      by (smt (verit, ccfv_SIG) IntE Int_mono c  S  T is_open S order.trans inf.orderE
          is_ball_def is_open_imp_in_Qp' nested_balls)
      (* larger radius index = smaller ball in ultrametric *)
    then show "k. B⇘k⇙[c]  S  T" by blast
  qed
qed (fastforce simp: is_open_def)

text ‹Agreement on the notions of open set.›
lemma openin_padic_topology: "openin padic_topology = is_open"
  unfolding padic_topology_def
  using istopology_padic topology_inverse' by blast

subsection ‹Bridging lemmas — connect old and new frameworks›

lemma topspace_padic: "topspace padic_topology = carrier Qp"
proof
  show "topspace padic_topology  carrier Qp"
    by (metis is_open_def openin_padic_topology openin_topspace)
  show "carrier Qp  topspace padic_topology"
    by (simp add: c_ball_in_Qp is_openI openin_padic_topology openin_subset)
qed

lemma openin_ball:
  assumes "c  carrier Qp"
  shows "openin padic_topology (B⇘n⇙[c])"
  using openin_padic_topology ball_is_open is_ball_def assms
  by auto

lemma interior_eq:
  assumes "U  carrier Qp"
  shows "interior U = Abstract_Topology.interior_of padic_topology U"
  by (metis assms interiorI interior_of_unique interior_open interior_subset openin_padic_topology)

subsection ‹Main topological results in the standard framework›

text ‹Balls are open.›
lemma ball_openin_padic: "is_ball B  openin padic_topology B"
  using openin_padic_topology ball_is_open by simp

text ‹Hensel's lemma consequence: compactness of $\mathbb{Z}_p$.›

text ‹Open decomposition into maximal balls.›
lemma open_max_ball_decomposition:
  assumes "openin padic_topology U" "U  topspace padic_topology"
  shows "U = (max_balls U)"
proof -
  have "(max_balls U)  carrier Qp"
    using is_ball_imp_in_Qp is_max_ball_of_def max_balls_def by auto
  moreover have "interior U = {x  carrier Qp. Bmax_balls U. x  B}"
    using max_balls_interior assms is_open_def openin_padic_topology topspace_padic by auto
  then have "U = {x  carrier Qp. Bmax_balls U. x  B}"
    using assms(1) local.open_interior openin_padic_topology by force
  ultimately show ?thesis by auto
qed

end

subsection ‹The $p$-adic metric on $\mathbb{Q}_p$›

context padic_fields
begin

text ‹The $p$-adic absolute value / distance function.
  Convention: $|x|_p = p^{-\mathrm{val}(x)}$, with $|0|_p = 0$.›

definition padic_norm :: "padic_number  real" where
  "padic_norm x  (if x = 𝟬 then 0 else p powr (- real_of_int (ord x)))"

definition padic_dist :: "padic_number  padic_number  real" where
  "padic_dist x y  if x  carrier Qp  y  carrier Qp then padic_norm (x  y) else 0"

subsection ‹$\mathbb{Q}_p$ is a Metric\_space›

lemma padic_dist_nonneg: "0  padic_dist x y"
  by (simp add: padic_dist_def padic_norm_def)

lemma padic_dist_commute_aux: 
  assumes "x  carrier Qp" and "y  carrier Qp"
    shows"real_of_int p powr - real_of_int (ord (x  y)) = real_of_int p powr - real_of_int (ord (y  x))"
    using assms
    by (metis Qp.not_eq_diff_nonzero Qp.not_nonzero_memI Qp.plus_diff_simp 
        Qp.r_right_minus_eq diff_ord_nonzero)

lemma padic_dist_commute:
  shows "padic_dist x y = padic_dist y x"
  using padic_dist_commute_aux Qp.r_right_minus_eq padic_dist_def padic_norm_def by presburger

lemma padic_dist_zero:
  assumes "x  carrier Qp" "y  carrier Qp"
  shows "padic_dist x y = 0  x = y"
  unfolding padic_dist_def padic_norm_def
  using Qp.int_inc_zero Qp.nonzero_memE(2) assms p_nonzero by auto

lemma p_gt_1: "1 < (p :: int)"
  using prime prime_gt_1_int by auto

lemma p_ge_1_real: "(1 :: real)  real_of_int p"
  using p_gt_1 by linarith

lemma p_gt_1_real: "(1 :: real) < real_of_int p"
  using p_gt_1 by linarith

lemma diff_sum: 
  assumes "x  carrier Qp" "y  carrier Qp" "z  carrier Qp"
  shows "x  z = (x  y)  (y  z)"
  by (metis Qp.minus_a_inv Qp_diff_diff a_minus_def assms)

lemma padic_norm_ultrametric:
  assumes "a  carrier Qp" "b  carrier Qp"
  shows "padic_norm (a  b)  max (padic_norm a) (padic_norm b)"
proof (cases "a  b = 𝟬")
  case True
  then have "padic_norm (a  b) = 0" unfolding padic_norm_def by simp
  then show ?thesis using padic_norm_def powr_non_neg
    by (simp add: le_max_iff_disj)
next
  case ab_nz: False
  then have ab_nonzero: "a  b  nonzero Qp"
    using assms Qp.nonzero_memI Qp.add.m_closed by auto
  have val_ineq: "min (val a) (val b)  val (a  b)"
    using val_ultrametric assms by auto
  show ?thesis
  proof (cases "a = 𝟬  b = 𝟬")
    case True
    then show ?thesis unfolding padic_norm_def
      using assms by fastforce
  next
    case False
    then have ord_ineq: "min (ord a) (ord b)  ord (a  b)"
      using Qp.nonzero_memI ab_nonzero assms ord_ultrametric by presburger
    then have "p powr (- real_of_int (ord (a  b))) 
            max (p powr (- real_of_int (ord a))) (p powr (- real_of_int (ord b)))"
      using le_max_iff_disj ord_ineq p_gt_1_real by fastforce
    then show ?thesis
      using padic_norm_def False ab_nz by auto
  qed
qed

lemma padic_dist_ultrametric:
  assumes "x  carrier Qp" "y  carrier Qp" "z  carrier Qp"
  shows "padic_dist x z  max (padic_dist x y) (padic_dist y z)"
proof (cases "x = z")
  case True
  then have "padic_dist x z = 0" using assms padic_dist_zero by auto
  then show ?thesis using padic_dist_nonneg[of x y] padic_dist_nonneg[of y z] by simp
next
  case xz: False
  have "padic_norm (x  z)  max (padic_norm (x  y)) (padic_norm (y  z))"
    by (metis Qp.minus_closed assms diff_sum padic_norm_ultrametric)
  then show ?thesis
    using assms unfolding padic_dist_def by auto
qed

text ‹The ultrametric inequality implies the triangle inequality.›
lemma padic_dist_triangle:
  assumes "x  carrier Qp" "y  carrier Qp" "z  carrier Qp"
  shows "padic_dist x z  padic_dist x y + padic_dist y z"
  using padic_dist_ultrametric[OF assms] padic_dist_nonneg
  by (metis add_increasing add_increasing2 max_def)

interpretation padic: Metric_space "carrier Qp" padic_dist
proof
  fix x y
  show "0  padic_dist x y"
    by (simp add: padic_dist_nonneg)
  show "padic_dist x y = padic_dist y x"
    using padic_dist_commute by auto
  assume "x  carrier Qp" and "y  carrier Qp"
  then show "(padic_dist x y = 0) = (x = y)"
    using padic_dist_zero by auto
  fix z assume "z  carrier Qp"
  then show "padic_dist x z  padic_dist x y + padic_dist y z"
    by (simp add: x  carrier Qp y  carrier Qp padic_dist_triangle)
qed


text ‹Key correspondence:
  @{term c_ball n c} $= \{x \in \mathrm{carrier}\; \mathbb{Q}_p \mid \mathrm{val}(x - c) \ge n\}$
  $= \{x \in \mathrm{carrier}\; \mathbb{Q}_p \mid \mathrm{padic\_dist}\; c\; x \le p^{-n}\}$
  $=$ @{term padic.mcball c (p powr (-n))}.›

lemma padic_dist_as_norm:
  assumes "x  carrier Qp" "y  carrier Qp"
  shows "padic_dist x y = padic_norm (x  y)"
  unfolding padic_dist_def using assms by auto

lemma c_ball_eq_mcball:
  assumes "c  carrier Qp"
  shows "c_ball n c = padic.mcball c (real_of_int p powr (- real_of_int n))"
proof (rule Set.set_eqI)
  fix x
  show "x  c_ball n c  x  padic.mcball c (real_of_int p powr (- real_of_int n))"
  proof
    assume xin: "x  c_ball n c"
    then have x_car: "x  carrier Qp" and val_ge: "eint n  val (x  c)"
      using c_ball_def by auto
    show "x  padic.mcball c (real_of_int p powr (- real_of_int n))"
      unfolding padic.in_mcball
    proof (intro conjI)
      show "c  carrier Qp" using assms by auto
      show "x  carrier Qp" using x_car by auto
      show "padic_dist c x  real_of_int p powr (- real_of_int n)"
      proof (cases "x = c")
        case True
        then show ?thesis using assms padic_dist_zero powr_non_neg by auto
      next
        case False
        then have xc_nz: "x  c  nonzero Qp"
          using x_car assms Qp.not_eq_diff_nonzero by auto
        have "val (x  c) = eint (ord (x  c))" using val_ord xc_nz by auto
        then have ord_ge: "n  ord (x  c)" using val_ge by simp
        have "padic_dist c x = padic_norm (x  c)"
          by (metis assms padic_dist_as_norm padic_dist_commute x_car)
        also have " = p powr (- real_of_int (ord (x  c)))"
          using padic_norm_def Qp.nonzero_memE(2)[OF xc_nz] by auto
        also have "  p powr (- real_of_int n)"
          using powr_mono p_ge_1_real ord_ge by auto
        finally show ?thesis .
      qed
    qed
  next
    assume xin: "x  padic.mcball c (real_of_int p powr (- real_of_int n))"
    then have x_car: "x  carrier Qp" and dist_le: "padic_dist c x  p powr (- real_of_int n)"
      using padic.in_mcball by auto
    show "x  c_ball n c"
    proof (cases "x = c")
      case True then show ?thesis
        using assms c_ball_center_in is_ball_def by blast
    next
      case False
      then have xc_nz: "x  c  nonzero Qp"
        using x_car assms Qp.not_eq_diff_nonzero by auto
      have "padic_dist c x = padic_norm (x  c)"
        by (metis assms padic.commute padic_dist_as_norm x_car)
      also have " = p powr (- real_of_int (ord (x  c)))"
        using padic_norm_def Qp.nonzero_memE(2)[OF xc_nz] by auto
      finally have "p powr (- real_of_int (ord (x  c)))  p powr (- real_of_int n)"
        using dist_le by linarith
      then have "- real_of_int (ord (x  c))  - real_of_int n"
        using powr_le_cancel_iff[OF p_gt_1_real] by auto
      then have "eint n  val (x  c)"
        using val_ord xc_nz by auto
      then show ?thesis using c_ballI x_car by auto
    qed
  qed
qed

text ‹Open balls in the metric sense correspond to @{term c_ball} with shifted index.›
lemma mball_eq_c_ball:
  assumes "c  carrier Qp"
  shows "padic.mball c (real_of_int p powr (- real_of_int n)) = c_ball (n + 1) c"
proof (rule Set.set_eqI)
  fix x
  show "x  padic.mball c (real_of_int p powr (- real_of_int n))  x  c_ball (n + 1) c"
  proof
    assume xin: "x  padic.mball c (real_of_int p powr (- real_of_int n))"
    then have x_car: "x  carrier Qp" and dist_lt: "padic_dist c x < p powr (- real_of_int n)"
      using padic.in_mball by auto
    show "x  c_ball (n + 1) c"
    proof (cases "x = c")
      case True
      then show ?thesis
        using assms c_ball_center_in is_ball_def by blast 
    next
      case False
      then have xc_nz: "x  c  nonzero Qp"
        using x_car assms Qp.not_eq_diff_nonzero by auto
      have "padic_dist c x = padic_norm (x  c)"
        by (metis assms padic.commute padic_dist_as_norm x_car)
      then have "p powr (- real_of_int (ord (x  c))) < p powr (- real_of_int n)"
        using dist_lt padic_norm_def Qp.nonzero_memE(2)[OF xc_nz] by auto
      then have "- real_of_int (ord (x  c)) < - real_of_int n"
        using powr_less_cancel_iff[OF p_gt_1_real] by auto
      then show ?thesis using val_ord xc_nz c_ballI x_car by auto
    qed
  next
    assume xin: "x  c_ball (n + 1) c"
    then have x_car: "x  carrier Qp" and val_ge: "eint (n + 1)  val (x  c)"
      using c_ball_def by auto
    show "x  padic.mball c (real_of_int p powr (- real_of_int n))"
      unfolding padic.in_mball
    proof (intro conjI)
      show "c  carrier Qp" "x  carrier Qp" using assms x_car by auto
      show "padic_dist c x < real_of_int p powr (- real_of_int n)"
      proof (cases "x = c")
        case True
        then show ?thesis
          using assms padic_dist_zero p_gt_1_real by auto
      next
        case False
        then have xc_nz: "x  c  nonzero Qp"
          using x_car assms Qp.not_eq_diff_nonzero by auto
        have "val (x  c) = eint (ord (x  c))" using val_ord xc_nz by auto
        then have "- real_of_int (ord (x  c)) < - real_of_int n" using val_ge by simp
        then have "p powr (- real_of_int (ord (x  c))) < p powr (- real_of_int n)"
          using p_gt_1_real by (simp add: powr_less_cancel_iff)
        moreover have "padic_dist c x = p powr (- real_of_int (ord (x  c)))"
        proof -
          have "padic_dist c x = padic_norm (x  c)"
            by (metis assms padic.commute padic_dist_as_norm x_car)
          also have " = p powr (- real_of_int (ord (x  c)))"
            using padic_norm_def Qp.nonzero_memE(2)[OF xc_nz] by auto
          finally show ?thesis .
        qed
        ultimately show ?thesis by linarith
      qed
    qed
  qed
qed

subsection ‹The metric topology equals @{term is_open}
lemma padic_topology_eq_mtopology:
  "openin padic.mtopology U  is_open U"
proof
  assume "openin padic.mtopology U"
  then have U_sub: "U  carrier Qp" and
    U_ball: "x. x  U  r>0. padic.mball x r  U"
    using padic.openin_mtopology by auto
  show "is_open U"
  proof (rule is_openI[OF U_sub])
    fix c assume c_in: "c  U"
    obtain r where r_pos: "r > 0" and r_sub: "padic.mball c r  U"
      using U_ball c_in by auto
    obtain n where n_large: "p powr (- real_of_int n) < r"
      by (meson ex_less_of_int less_log_iff minus_less_iff p_gt_1_real r_pos)
    have "c_ball (n + 1) c = padic.mball c (p powr (- real_of_int n))"
      using mball_eq_c_ball U_sub by (simp add: c_in in_mono)
    then show "k. c_ball k c  U" 
      using r_sub padic.mball_subset_concentric n_large by fastforce
  qed
next
  assume U_open: "is_open U"
  show "openin padic.mtopology U"
    unfolding padic.openin_mtopology
  proof (intro conjI allI impI)
    show "U  carrier Qp" using U_open is_open_imp_in_Qp by blast
  next
    fix x assume x_in: "x  U"
    then have x_car: "x  carrier Qp" using U_open is_open_imp_in_Qp by blast
    obtain n where n_sub: "c_ball n x  U"
      using U_open x_in is_open_def by auto
    have ball_eq: "padic.mball x (p powr (- real_of_int (n - 1))) = c_ball n x"
      using mball_eq_c_ball[OF x_car, of "n - 1"] by auto
    have r_pos: "0 < p powr (- real_of_int (n - 1))"
      using p_gt_1_real by simp
    show "r>0. padic.mball x r  U"
      using ball_eq n_sub r_pos by blast
  qed
qed

lemma padic_mtopology_eq: "padic.mtopology = padic_topology"
  using padic_topology_eq_mtopology openin_padic_topology
  by (intro topology.openin_inject[THEN iffD1] ext iffI; simp)


lemma mcball_is_open:
  assumes "c  carrier Qp" "0 < r"
  shows "openin padic.mtopology (padic.mcball c r)"
  unfolding padic.openin_mtopology
proof (intro conjI strip)
  show "padic.mcball c r  carrier Qp"
    using padic.mcball_subset_mspace by auto
next
  fix y assume y_in: "y  padic.mcball c r"
  then have y_car: "y  carrier Qp" and dy: "padic_dist c y  r"
    using padic.in_mcball by auto
  show "ε>0. padic.mball y ε  padic.mcball c r"
  proof (intro exI conjI subsetI)
    show "0 < r" using assms by auto
  next
    fix z assume z_in: "z  padic.mball y r"
    then have z_car: "z  carrier Qp" and dyz: "padic_dist y z < r"
      using padic.in_mball by auto
    have "padic_dist c z  max (padic_dist c y) (padic_dist y z)"
      using padic_dist_ultrametric[OF assms(1) y_car z_car] by auto
    also have "  r" using dy dyz by simp
    finally show "z  padic.mcball c r"
      by (simp add: assms z_car)
  qed
qed

text ‹Equivalently, balls are clopen.›

lemma c_ball_open:
  assumes "c  carrier Qp"
  shows "openin padic.mtopology (c_ball n c)"
  using assms openin_ball padic_mtopology_eq by force

lemma c_ball_closed:
  assumes "c  carrier Qp"
  shows "closedin padic.mtopology (c_ball n c)"
  using assms c_ball_eq_mcball by force

lemma c_ball_clopen:
  assumes "c  carrier Qp"
  shows "openin padic.mtopology (c_ball n c)  closedin padic.mtopology (c_ball n c)"
  by (simp add: assms c_ball_closed c_ball_open)

text ‹Total disconnectedness.›
lemma padic_mtop_totally_disconnected:
  assumes "connectedin padic.mtopology S"
  shows "a. S  {a}"
proof (rule ccontr)
  assume neg: "¬(a. S  {a})"
  have S_sub: "S  carrier Qp"
    using assms connectedin_subset_topspace padic.topspace_mtopology by blast
  obtain x y where xy: "x  S" "y  S" "x  y"
    by (metis insertI1 neg subsetI)
  have x_car: "x  carrier Qp" and y_car: "y  carrier Qp"
    using S_sub xy by auto
  have xy_nz: "x  y  nonzero Qp"
    using xy x_car y_car Qp.not_eq_diff_nonzero by auto
  define n where "n = ord (x  y) + 1"
  have x_in_ball: "x  c_ball n x"
    using c_ball_center_in is_ball_def x_car by blast
  have y_not_in_ball: "y  c_ball n x"
  proof
    assume "y  c_ball n x"
    then have val_ge: "eint n  val (y  x)" using c_ballE by auto
    have yx_nz: "y  x  nonzero Qp"
      using xy x_car y_car Qp.not_eq_diff_nonzero by auto
    have "val (y  x) = eint (ord (y  x))" using val_ord[OF yx_nz] by auto
    then have n_le: "n  ord (y  x)" using val_ge by simp
    have "y  x =  (x  y)"
      using x_car y_car using Qp.minus_a_inv by blast
    then have "ord (y  x) = ord (x  y)"
      using ord_minus xy_nz by presburger
    then show False using n_le n_def by linarith
  qed
  have "S  c_ball n x  disjnt S (c_ball n x)"
    using connectedin_clopen_cases[OF assms] c_ball_closed 
    using openin_ball padic_mtopology_eq x_car by auto
  then show False
    by (meson disjnt_iff in_mono x_in_ball xy y_not_in_ball)
qed

text ‹Nested balls — reproved from the ultrametric inequality.›
lemma ultrametric_nested:
  assumes "padic.mcball x r  padic.mcball y s  {}"
  shows "padic.mcball x r  padic.mcball y s  padic.mcball y s  padic.mcball x r"
proof -
  obtain z where z_xr: "z  padic.mcball x r" and z_ys: "z  padic.mcball y s"
    using assms by blast
  then have x_car: "x  carrier Qp" and y_car: "y  carrier Qp" and z_car: "z  carrier Qp"
    and dxz: "padic_dist x z  r" and dyz: "padic_dist y z  s"
    using padic.in_mcball by auto
  have dzx: "padic_dist z x  r" using dxz padic_dist_commute by simp
  have dzy: "padic_dist z y  s" using dyz padic_dist_commute by simp
  show ?thesis
  proof (cases "r  s")
    case True
    show ?thesis
    proof (intro disjI1 subsetI)
      fix w assume w_in: "w  padic.mcball x r"
      then have w_car: "w  carrier Qp" and dxw: "padic_dist x w  r"
        using padic.in_mcball by auto
      have "padic_dist z w  max (padic_dist z x) (padic_dist x w)"
        using padic_dist_ultrametric[OF z_car x_car w_car] by auto
      also have "  r" using dzx dxw by simp
      finally have dzw: "padic_dist z w  r" .
      have "padic_dist y w  max (padic_dist y z) (padic_dist z w)"
        using padic_dist_ultrametric[OF y_car z_car w_car] by auto
      also have "  s" using dyz dzw True by simp
      finally show "w  padic.mcball y s"
        using padic.in_mcball y_car w_car by auto
    qed
  next
    case False
    then have sr: "s  r" by simp
    show ?thesis
    proof (intro disjI2 subsetI)
      fix w assume w_in: "w  padic.mcball y s"
      then have w_car: "w  carrier Qp" and dyw: "padic_dist y w  s"
        using padic.in_mcball by auto
      have "padic_dist z w  max (padic_dist z y) (padic_dist y w)"
        using padic_dist_ultrametric[OF z_car y_car w_car] by auto
      also have "  s" using dzy dyw by simp
      finally have dzw: "padic_dist z w  s" .
      have "padic_dist x w  max (padic_dist x z) (padic_dist z w)"
        using padic_dist_ultrametric[OF x_car z_car w_car] by auto
      also have "  r" using dxz dzw sr by simp
      finally show "w  padic.mcball x r"
        using padic.in_mcball x_car w_car by auto
    qed
  qed
qed

subsection ‹Closedness and disconnectedness›

text ‹Balls are also closed (clopen).›
lemma closedin_ball:
  assumes "c  carrier Qp"
  shows "closedin padic_topology (B⇘n⇙[c])"
  using c_ball_clopen[OF assms] padic_mtopology_eq by simp

lemma ball_closedin_padic:
  "is_ball B  closedin padic_topology B"
  using closedin_ball is_ball_def by auto

text ‹The $p$-adic topology is totally disconnected.›
lemma padic_totally_disconnected:
  assumes "connectedin padic_topology S"
  shows "a. S  {a}"
  using padic_mtop_totally_disconnected assms padic_mtopology_eq by simp

subsection ‹Completeness›

text ‹$\mathbb{Q}_p$ is complete: every Cauchy sequence converges.
  This uses @{term Metric_space.mcomplete}.›

theorem padic_complete: "padic.mcomplete"
  unfolding padic.mcomplete_def
proof (intro allI impI)
  fix σ assume cauchy: "padic.MCauchy σ"

  text ‹Step 1: Reduce to bounded sequences.
    Every Cauchy sequence in $\mathbb{Q}_p$ is eventually in some ball @{term c_ball 0 c}.
    By rescaling (multiplying by a power of $p$), we can reduce to a
    sequence in $\mathbb{Z}_p$ (i.e., with non-negative valuation).›
  have σ_range: "range σ  carrier Qp"
    using cauchy padic.MCauchy_def by auto
  obtain c N where c_car: "c  carrier Qp"
    and eventually_in_ball: "m  N. σ m  c_ball 0 c"
  proof -
    obtain N where hN: "n n'. N  n  N  n'  padic_dist (σ n) (σ n') < 1"
      using cauchy[unfolded padic.MCauchy_def] by (meson zero_less_one)
    have σN_car: "σ N  carrier Qp"
      using σ_range by auto
    have "m  N. σ m  c_ball 0 (σ N)"
    proof (intro allI impI)
      fix m assume "N  m"
      then have "padic_dist (σ N) (σ m) < 1" using hN by auto
      then have "padic_dist (σ N) (σ m)  real_of_int p powr (- real_of_int 0)"
        using p_ge_1_real by simp
      then have "σ m  padic.mcball (σ N) (real_of_int p powr (- real_of_int 0))"
        using padic.in_mcball σN_car σ_range by auto
      then show "σ m  c_ball 0 (σ N)"
        using c_ball_eq_mcball[OF σN_car] by simp
    qed
    then show thesis using that σN_car by blast
  qed

  text ‹Step 2: Translate metric Cauchy to val-based Cauchy.
    Show that @{term padic.MCauchy} (in @{term padic_dist}) implies that
    for all $n$, eventually $\mathrm{val}(\sigma_m - \sigma_k) \ge n$.›
  have val_cauchy: "K. m k. m  K  k  K  eint n  val (σ m  σ k)" for n
  proof -
    have "real_of_int p powr (- real_of_int n) > 0"
      using p_gt_1 by (simp add: powr_gt_zero)
    then obtain K where hK: "m k. K  m  K  k  padic_dist (σ m) (σ k) < real_of_int p powr (- real_of_int n)"
      using cauchy[unfolded padic.MCauchy_def] by (meson less_le_not_le)
    show "K. m k. m  K  k  K  eint n  val (σ m  σ k)"
    proof (intro exI allI impI)
      fix m k assume "K  m" "K  k"
      then have dist_bound: "padic_dist (σ m) (σ k) < real_of_int p powr (- real_of_int n)"
        using hK by auto
      have σm_car: "σ m  carrier Qp" and σk_car: "σ k  carrier Qp"
        using σ_range by auto
      have diff_car: "σ m  σ k  carrier Qp"
        using Qp.minus_closed σm_car σk_car by auto
      show "eint n  val (σ m  σ k)"
      proof (cases "σ m  σ k = 𝟬")
        case True
        then show ?thesis using val_zero by simp
      next
        case False
        then have diff_nz: "σ m  σ k  nonzero Qp"
          using Qp.nonzero_memI diff_car by auto
        have norm_eq: "padic_norm (σ m  σ k) = real_of_int p powr (- real_of_int (ord (σ m  σ k)))"
          using padic_norm_def False by auto
        have "padic_norm (σ m  σ k) < real_of_int p powr (- real_of_int n)"
          using dist_bound padic_dist_as_norm σm_car σk_car by auto
        then have "- real_of_int (ord (σ m  σ k)) < - real_of_int n"
          using local.norm_eq p_gt_1_real by force
        then have "n  ord (σ m  σ k)" by linarith
        then show ?thesis
          using val_ord diff_nz eint_ord_code(1) by auto
      qed
    qed
  qed

  text ‹Step 3: Reduce to $\mathbb{Z}_p$.
    After shifting/rescaling, express the (tail of the) sequence as
    $\iota \circ s$ for some $s : \mathbb{N} \to \mathrm{carrier}\; \mathbb{Z}_p$,
    then show $s$ is @{term is_Zp_cauchy}.›
  define s where "s m = to_Zp (σ m  c)" for m
  have s_Zp: "s m  carrier Zp" for m
  proof -
    have "σ m  c  carrier Qp" using Qp.minus_closed c_car σ_range by auto
    then show ?thesis unfolding s_def using to_Zp_closed by auto
  qed
  have diff_in_val_ring: "σ m  c  𝒪p" if "N  m" for m
  proof -
    have "σ m  c_ball 0 c" using that eventually_in_ball by auto
    then show ?thesis
      by (simp add: Qp_val_ringI c_ballE c_car zero_eint_def)
  qed
  have s_eq: "σ m = ι (s m)  c" if "N  m" for m
  proof -
    have in_val: "σ m  c  𝒪p" using diff_in_val_ring that by auto
    have "ι (s m) = ι (to_Zp (σ m  c))" unfolding s_def by simp
    also have " = σ m  c" using to_Zp_inc[OF in_val] by simp
    finally have inc_eq: "ι (s m) = σ m  c" .
    have "σ m  carrier Qp" using σ_range by auto
    then show "σ m = ι (s m)  c"
      by (metis inc_eq c_car Qp.add.inv_solve_right Qp.minus_closed a_minus_def) 
  qed
  have s_closed: "s  carrier Zpω"
    using s_Zp closed_seqs_memI by auto
  have s_val_cauchy: "M. m k. M < m  M < k  eint n < val_Zp_dist (s m) (s k)" for n
  proof -
    obtain K where hK: "m k. m  K  k  K  eint (n + 1)  val (σ m  σ k)"
      using val_cauchy by (meson le_cases)
    define K' where "K' = max N K"
    show "M. m k. M < m  M < k  eint n < val_Zp_dist (s m) (s k)"
    proof (intro exI strip)
      fix m k assume mk: "K' < m  K' < k"
      then have hm: "m  N" "m  K" and hk: "k  N" "k  K"
        unfolding K'_def by auto
      have sm_car: "s m  carrier Zp" and sk_car: "s k  carrier Zp"
        using s_Zp by auto
      have diff_Zp: "s m Zps k  carrier Zp"
        using Zp.minus_closed sm_car sk_car by auto
      have "val_Zp_dist (s m) (s k) = val_Zp (s m Zps k)"
        using val_Zp_dist_def by auto
      also have " = val (ι (s m Zps k))"
        using val_of_inc[OF diff_Zp] by simp
      also have " = val (ι (s m)  ι (s k))"
        using inc_of_diff[OF sm_car sk_car] by simp
      also have " = val ((σ m  c)  (σ k  c))"
        using diff_in_val_ring hk(1) hm(1) s_def to_Zp_inc by presburger
      also have " = val (σ m  σ k)"
        by (metis Qp_diff_diff c_ballE(1) c_car eventually_in_ball hk(1) hm(1))
      finally have val_eq: "val_Zp_dist (s m) (s k) = val (σ m  σ k)" .
      have "eint (n + 1)  val (σ m  σ k)"
        using hK hm(2) hk(2) by auto
      then show "eint n < val_Zp_dist (s m) (s k)"
        using val_eq Suc_ile_eq by auto
    qed
  qed
  have s_cauchy: "is_Zp_cauchy s"
    using s_closed s_val_cauchy is_Zp_cauchy_def by auto

  text ‹Step 4: Apply $\mathbb{Z}_p$ completeness.
    Use @{thm [source] is_Zp_cauchy_imp_has_limit} to get the limit in $\mathbb{Z}_p$,
    then map it back to $\mathbb{Q}_p$.›

  define a where "a = res_lim s"
  have a_Zp: "a  carrier Zp"
    using s_cauchy res_lim_in_Zp a_def by auto

  have Zp_conv: "Zp_converges_to s a"
    using is_Zp_cauchy_imp_has_limit s_cauchy a_def by auto

  text ‹Step 5: Translate $\mathbb{Z}_p$ convergence back to $\mathbb{Q}_p$ metric convergence.
    Show @{term Zp_converges_to s a} implies
    @{term limitin padic.mtopology σ L sequentially}.
    Key bridge: @{thm [source] val_of_inc}, @{thm [source] inc_of_diff}, and the characterization
    @{thm [source] padic.limitin_metric_dist_null}.›

  define L where "L = ι a  c"
  have L_car: "L  carrier Qp"
    unfolding L_def using Qp.a_closed[OF inc_closed[OF a_Zp] c_car] by simp
  have inc_a_car: "ι a  carrier Qp" using inc_closed a_Zp by auto
  have "limitin padic.mtopology σ L sequentially"
    unfolding padic.limitin_metric_dist_null
  proof (intro conjI)
    show "L  carrier Qp" by (rule L_car)
  next
    show "F m in sequentially. σ m  carrier Qp"
      using σ_range by (simp add: eventually_sequentially, intro exI[of _ 0]) auto
  next
    show "((λm. padic_dist (σ m) L)  0) sequentially"
    proof (rule metric_LIMSEQ_I)
      fix r :: real assume "r > 0"
      define n where "n = - log (real_of_int p) r + 1"
      ― ‹Find n such that @{term p powr (-n) < r}
      have n_bound: "real_of_int n > - log (real_of_int p) r"
        unfolding n_def using le_of_int_ceiling[of "- log (real_of_int p) r"]
        by linarith
      have p_powr_bound: "real_of_int p powr (- real_of_int n) < r"
        using 0 < r n_bound p_gt_1_real powr_less_iff by auto
      have "k. m>k. eint n < val_Zp (s m Zpa)"
        using Zp_conv[unfolded Zp_converges_to_def] by blast
      then obtain K where hK: "m>K. eint n < val_Zp (s m Zpa)"
        by auto
      ― ‹Take threshold = max K N + 1›
      define M where "M = max (nat (K + 1)) N"
      show "no. mno. dist ((λm. padic_dist (σ m) L) m) 0 < r"
      proof (intro exI allI impI)
        fix m assume hm: "M  m"
        have m_ge_N: "m  N" and m_gt_K: "m > K" 
          using hm unfolding M_def by linarith+
        have σm_car: "σ m  carrier Qp" using σ_range by auto
        have sm_car: "s m  carrier Zp" using s_Zp by auto
        have diff_car: "s m Zpa  carrier Zp"
          using Zp.minus_closed[OF sm_car a_Zp] by auto
        ― ‹Key: @{term ι (s m)  ι a = σ m  L}
        have inc_sm: "ι (s m) = σ m  c"
          using s_eq m_ge_N σm_car c_car
          by (metis diff_in_val_ring s_def to_Zp_inc)
        have "ι (s m Zpa) = ι (s m)  ι a"
          using inc_of_diff[OF sm_car a_Zp] by simp
        also have " = (σ m  c)  ι a"
          using inc_sm by simp
        also have " = σ m  (c  ι a)"
          using Qp.right_inv_add[OF c_car inc_a_car σm_car] by simp
        also have " = σ m  (ι a  c)"
          using Qp.a_comm[OF c_car inc_a_car] by simp
        also have " = σ m  L" unfolding L_def by simp
        finally have key_eq: "ι (s m Zpa) = σ m  L" .
        ― ‹Get the val bound›
        have val_bound: "eint n < val_Zp (s m Zpa)"
          using hK m_gt_K by auto
        have val_inc: "val_Zp (s m Zpa) = val (ι (s m Zpa))"
          using val_of_inc[OF diff_car] by simp
        have val_diff: "eint n < val (σ m  L)"
          using val_bound val_inc key_eq by simp
        ― ‹Convert to @{term padic_dist} bound›
        have diff_car2: "σ m  L  carrier Qp"
          using Qp.minus_closed[OF σm_car L_car] by simp
        have dist_eq: "padic_dist (σ m) L = padic_norm (σ m  L)"
          using padic_dist_as_norm[OF σm_car L_car] by simp
        show "dist ((λm. padic_dist (σ m) L) m) 0 < r"
        proof (cases "σ m  L = 𝟬")
          case True
          then have "padic_dist (σ m) L = 0"
            using dist_eq padic_norm_def by simp
          then show ?thesis using r > 0 by (simp add: dist_real_def)
        next
          case False
          have nz: "σ m  L  nonzero Qp"
            using Qp.nonzero_memI[OF diff_car2 False] by simp
          have val_eq: "val (σ m  L) = eint (ord (σ m  L))"
            using val_ord[OF nz] by simp
          have ord_bound: "n < ord (σ m  L)"
            using val_diff val_eq by simp
          have neg_ord_bound: "- real_of_int (ord (σ m  L)) < - real_of_int n"
            using ord_bound by linarith
          have norm_eq: "padic_norm (σ m  L) = real_of_int p powr (- real_of_int (ord (σ m  L)))"
            using padic_norm_def False by simp
          have "padic_norm (σ m  L) < real_of_int p powr (- real_of_int n)"
            using norm_eq powr_less_mono[OF neg_ord_bound p_gt_1_real] by simp
          then have "padic_dist (σ m) L < r"
            using dist_eq p_powr_bound by linarith
          then show ?thesis
            using padic_dist_nonneg[of "σ m" L] by (simp add: dist_real_def)
        qed
      qed
    qed
  qed
  then show "x. limitin padic.mtopology σ x sequentially"
    by blast
qed

end
end