Theory Elementary_Ultrametric_Spaces


(* Author: Benoît Ballenghien, Université Paris-Saclay, CNRS, ENS Paris-Saclay, LMF
   Author: Benjamin Puyobro, Université Paris-Saclay, IRT SystemX, CNRS, ENS Paris-Saclay, LMF
   Author: Burkhart Wolff, Université Paris-Saclay, CNRS, ENS Paris-Saclay, LMF *)

(*<*)
theory Elementary_Ultrametric_Spaces
  imports "HOL-Analysis.Elementary_Metric_Spaces"
begin
  (*>*)


section ‹Definition›

setup Sign.add_const_constraint (const_namedist, NONE)
  ― ‹To be able to use constdist out of the classmetric_space class.›

class ultrametric_space = uniformity_dist + open_uniformity +
  assumes dist_eq_0_iff [simp]: dist x y = 0  x = y
    and ultrametric_dist_triangle2: dist x y  max (dist x z) (dist y z)
begin

subclass metric_space
proof (unfold_locales)
  show dist x y = 0  x = y for x y by simp
next
  show dist x y  dist x z + dist y z for x y z
    by (rule order_trans[OF ultrametric_dist_triangle2, of _ z], simp)
      (metis local.dist_eq_0_iff ultrametric_dist_triangle2 max.idem)
qed

end

setup Sign.add_const_constraint (const_namedist, SOME typ'a :: metric_space  'a  real)
  ― ‹Back to normal.›


class complete_ultrametric_space = ultrametric_space +
  assumes Cauchy_convergent: Cauchy X  convergent X
begin

subclass complete_space by unfold_locales (fact Cauchy_convergent)

end



section ‹Properties on Balls›

text ‹In ultrametric space, balls satisfy very strong properties.›

context ultrametric_space begin

lemma ultrametric_dist_triangle: dist x z  max (dist x y) (dist y z)
  using ultrametric_dist_triangle2 [of x z y] by (simp add: dist_commute)

lemma ultrametric_dist_triangle3: dist x y  max (dist a x) (dist a y)
  using ultrametric_dist_triangle2 [of x y a] by (simp add: dist_commute)

end



subsection ‹Balls are centered everywhere›

context fixes x :: 'a :: ultrametric_space begin

text ‹The best way to do this would be to work in the context localeultrametric_space.
      Unfortunately, constball, constcball, etc. are not defined inside
      the context localemetric_space but through a sort constraint.›

lemma ultrametric_every_point_of_ball_is_centre :
  ball y r = ball x r if y  ball x r 
proof (unfold set_eq_iff, rule allI)
  from y  ball x r have * : dist x y < r by simp
  show z  ball y r  z  ball x r for z
    using ultrametric_dist_triangle[of x z y]
      "*" ultrametric_dist_triangle[of y z x]
    by (intro iffI) (simp_all add: dist_commute)
qed


lemma ultrametric_every_point_of_cball_is_centre :
  cball y r = cball x r if y  cball x r
proof (unfold set_eq_iff, rule allI)
  from y  cball x r have * : dist x y  r by simp
  show z  cball y r  z  cball x r for z
    using ultrametric_dist_triangle[of x z y]
      "*" ultrametric_dist_triangle[of y z x]
    by (intro iffI) (simp_all add: dist_commute)
qed

end



subsection ‹Balls are ``clopen''›

text ‹Balls are both open and closed.›

context fixes x :: 'a :: ultrametric_space begin

lemma ultrametric_open_cball [intro, simp] : open (cball x r) if 0 < r
proof (rule openI) 
  fix y assume y  cball x r
  hence cball y r = cball x r
    by (rule ultrametric_every_point_of_cball_is_centre)
  hence ball y (r / 2)  cball x r
    by (metis ball_subset_cball cball_divide_subset_numeral subset_trans)
  moreover have 0 < r / 2 by (simp add: 0 < r)
  ultimately show e>0. ball y e  cball x r by blast
qed

lemma closed (cball y r) by (fact closed_cball)


lemma ultrametric_closed_ball [intro, simp]: closed (ball x r) if 0  r
proof (cases r = 0)
  show r = 0  closed (ball x r) by simp
next
  assume r  0
  with 0  r have 0 < r by simp
  show closed (ball x r)
  proof (unfold closed_def)
    have - ball x r = (z  - ball x r. ball z r)
    proof (intro subset_antisym subsetI)
      from 0 < r show z  - ball x r  z  (z- ball x r. ball z r) for z
        by (meson UN_iff centre_in_ball)
    next
      show z  (z  - ball x r. ball z r)  z  - ball x r for z
        by simp (metis ComplD dist_commute mem_ball
            ultrametric_every_point_of_ball_is_centre)
    qed
    show open (- ball x r) by (subst ?this, rule open_Union, simp)
  qed
qed

lemma ultrametric_open_sphere [intro, simp] : 0 < r  open (sphere x r)
  by (fold cball_diff_eq_sphere) (simp add: open_Diff order_le_less)

lemma closed_sphere [intro, simp] : closed (sphere y r)
  by (metis open_ball cball_diff_eq_sphere closed_Diff closed_cball)

end



subsection ‹Balls are disjoint or contained›

context fixes x :: 'a :: ultrametric_space begin

lemma ultrametric_ball_ball_disjoint_or_subset:
  ball x r  ball y s = {}  ball x r  ball y s 
   ball y s  ball x r
proof (unfold disj_imp, intro impI)
  assume ball x r  ball y s  {} ¬ ball x r  ball y s
  from ball x r  ball y s  {}
  obtain z where z  ball x r and z  ball y s by blast
  with ultrametric_every_point_of_ball_is_centre
  have ball x r = ball z r and ball y s = ball z s by auto
  with ¬ ball x r  ball y s have s < r by auto
  with ball x r = ball z r and ball y s = ball z s
  show ball y s  ball x r by auto
qed

lemma ultrametric_ball_cball_disjoint_or_subset:
  ball x r  cball y s = {}  ball x r  cball y s 
   cball y s  ball x r
proof (unfold disj_imp, intro impI)
  assume ball x r  cball y s  {} ¬ ball x r  cball y s
  from ball x r  cball y s  {}
  obtain z where z  ball x r and z  cball y s by blast
  with ultrametric_every_point_of_ball_is_centre
    ultrametric_every_point_of_cball_is_centre
  have ball x r = ball z r cball y s = cball z s by blast+
  with ¬ ball x r  cball y s have s < r by auto
  with ball x r = ball z r and cball y s = cball z s
  show cball y s  ball x r by auto
qed

corollary ultrametric_cball_ball_disjoint_or_subset:
  cball x r  ball y s = {}  cball x r  ball y s 
   ball y s  cball x r
  using Elementary_Ultrametric_Spaces.ultrametric_ball_cball_disjoint_or_subset by blast

lemma ultrametric_cball_cball_disjoint_or_subset:
  cball x r  cball y s = {}  cball x r  cball y s 
   cball y s  cball x r
proof (unfold disj_imp, intro impI)
  assume cball x r  cball y s  {} ¬ cball x r  cball y s
  from cball x r  cball y s  {}
  obtain z where z  cball x r and z  cball y s by blast
  with ultrametric_every_point_of_cball_is_centre
  have cball x r = cball z r cball y s = cball z s by auto
  with ¬ cball x r  cball y s have s < r by auto
  with cball x r = cball z r and cball y s = cball z s
  show cball y s  cball x r by auto
qed

end



subsection ‹Distance to a Ball›

context fixes a :: 'a :: ultrametric_space begin

lemma ultrametric_equal_distance_to_ball:
  dist a y = dist a z if a  ball x r y  ball x r z  ball x r
proof (rule order_antisym)
  show dist a y  dist a z
    by (rule order_trans[OF ultrametric_dist_triangle[of a y z]], simp)
      (metis dist_commute dual_order.strict_trans2 linorder_linear
        mem_ball that ultrametric_every_point_of_ball_is_centre)
next
  show dist a z  dist a y
    by (rule order_trans[OF ultrametric_dist_triangle[of a z y]], simp)
      (metis dist_commute dual_order.strict_trans2 linorder_linear
        mem_ball that ultrametric_every_point_of_ball_is_centre)
qed


lemma ultrametric_equal_distance_to_cball:
  dist a y = dist a z if a  cball x r y  cball x r z  cball x r
proof (rule order_antisym)
  show dist a y  dist a z
    by (rule order_trans[OF ultrametric_dist_triangle[of a y z]], simp)
      (metis dist_commute dual_order.trans linorder_linear mem_cball
        that ultrametric_every_point_of_cball_is_centre)
next
  show dist a z  dist a y
    by (rule order_trans[OF ultrametric_dist_triangle[of a z y]], simp)
      (metis dist_commute dual_order.trans linorder_linear mem_cball
        that ultrametric_every_point_of_cball_is_centre)
qed

end


context fixes x :: 'a :: ultrametric_space begin

lemma ultrametric_equal_distance_between_ball_ball:
  ball x r  ball y s = {} 
   d. a  ball x r. b  ball y s. dist a b = d
  by (metis disjoint_iff dist_commute ultrametric_equal_distance_to_ball)          

lemma ultrametric_equal_distance_between_ball_cball:
  ball x r  cball y s = {} 
   d. a  ball x r. b  cball y s. dist a b = d
  by (metis disjoint_iff dist_commute ultrametric_equal_distance_to_ball
      ultrametric_equal_distance_to_cball)

lemma ultrametric_equal_distance_between_cball_ball:
  cball x r  ball y s = {} 
   d. a  cball x r. b  ball y s. dist a b = d
  by (metis disjoint_iff_not_equal dist_commute ultrametric_equal_distance_to_ball
      ultrametric_equal_distance_to_cball)

lemma ultrametric_equal_distance_between_cball_cball:
  cball x r  cball y s = {} 
   d. a  cball x r. b  cball y s. dist a b = d
  by (metis disjoint_iff dist_commute ultrametric_equal_distance_to_cball)

end



section ‹Additional Properties›

text ‹Here are a few other interesting properties.›

subsection ‹Cauchy Sequences›

lemma (in ultrametric_space) ultrametric_dist_triangle_generalized:
  n < m  dist (σ n) (σ m)  (MAX l  {n..m - 1}. dist (σ l) (σ (Suc l)))
proof (induct m)
  show n < 0  dist (σ n) (σ 0)  (MAX l{n..0 - 1}. dist (σ l) (σ (Suc l))) by simp
next
  case (Suc m)
  show dist (σ n) (σ (Suc m))  (MAX l{n..Suc m - 1}. dist (σ l) (σ (Suc l)))
  proof (cases n = m)
    show n = m  dist (σ n) (σ (Suc m))  (MAX l{n..Suc m - 1}. dist (σ l) (σ (Suc l)))
      by simp
  next
    assume n  m
    with n < Suc m obtain m' where m = Suc m' n  m' 
      by (metis le_add1 less_Suc_eq less_imp_Suc_add)
    have {n..Suc m'} = {n..m-1}  {m}
      by (simp add: m = Suc m' n  m' atLeastAtMostSuc_conv le_Suc_eq)
    have dist (σ n) (σ (Suc m))  max (dist (σ n) (σ m)) (dist (σ m) (σ (Suc m)))
      by (simp add: ultrametric_dist_triangle)
    also have   max ((MAX l{n..m - 1}. dist (σ l) (σ (Suc l)))) (dist (σ m) (σ (Suc m)))
      using Suc.hyps Suc.prems n  m by linarith
    also have  = (MAX l{n..Suc m - 1}. dist (σ l) (σ (Suc l)))
      by (subst Max_Un[of _ ((λl. dist (σ l) (σ (Suc l))) ` {m}), simplified, symmetric])
        (simp_all add: m = Suc m' n  m' {n..Suc m'} = {n..m-1}  {m})
    finally show dist (σ n) (σ (Suc m))  (MAX l{n..Suc m - 1}. dist (σ l) (σ (Suc l))) .
  qed
qed


lemma (in ultrametric_space) ultrametric_Cauchy_iff:
  Cauchy σ  (λn. dist (σ (Suc n)) (σ n))  0
proof (rule iffI)
  assume Cauchy σ
  show (λn. dist (σ (Suc n)) (σ n))  0
  proof (unfold lim_sequentially, intro allI impI)
    fix ε :: real
    assume 0 < ε
    from Cauchy σ[unfolded Cauchy_altdef, rule_format, OF 0 < ε]
    show N. nN. dist (dist (σ (Suc n)) (σ n)) 0 < ε
      by (auto simp add: dist_commute)
  qed
next
  assume convergent : (λn. dist (σ (Suc n)) (σ n))  0
  show Cauchy σ
  proof (unfold Cauchy_altdef2, intro allI impI)
    fix ε :: real
    assume 0 < ε
    from convergent[unfolded lim_sequentially, rule_format, OF 0 < ε]
    obtain N where * : N  n  dist (σ (Suc n)) (σ n) < ε for n
      by (simp add: dist_real_def) blast

    have N < n  dist (σ n) (σ N) < ε for n
    proof (subst dist_commute, rule le_less_trans)
      show N < n  dist (σ N) (σ n)  (MAX l{N..n - 1}. dist (σ l) (σ (Suc l)))
        by (fact ultrametric_dist_triangle_generalized)
    next
      show N < n  (MAX l{N..n - 1}. dist (σ l) (σ (Suc l))) < ε
        by simp (metis "*" atLeastAtMost_iff dist_commute)
    qed
    with 0 < ε have N  n  dist (σ n) (σ N) < ε for n
      by (cases N = n) simp_all 
    thus N. nN. dist (σ n) (σ N) < ε by blast
  qed
qed



subsection ‹Isosceles Triangle Principle›

lemma (in ultrametric_space) ultrametric_isosceles_triangle_principle : 
  dist x z = max (dist x y) (dist y z) if dist x y  dist y z
proof (rule order_antisym)
  show dist x z  max (dist x y) (dist y z)
    by (fact ultrametric_dist_triangle)
next
  from dist x y  dist y z linorder_less_linear
  have dist x y < dist y z  dist y z < dist x y by blast
  with ultrametric_dist_triangle[of y z x]
    ultrametric_dist_triangle[of x y z]
  show max (dist x y) (dist y z)  dist x z
    by (elim disjE) (simp_all add: dist_commute)
qed



subsection ‹Distance to a convergent Sequence›

lemma ultrametric_dist_to_convergent_sequence_is_eventually_const :
  fixes σ :: nat  'a :: ultrametric_space
  assumes σ  Σ and x  Σ
  shows N. nN. dist (σ n) x = dist Σ x
proof -
  from x  Σ have 0 < dist x Σ by simp
  then obtain ε where 0 < ε ball x ε  ball Σ ε = {}
    by (metis centre_in_ball disjoint_iff mem_ball order_less_le
        ultrametric_every_point_of_ball_is_centre)

  from σ  Σ 0 < ε obtain N where N  n  σ n  ball Σ ε for n
    by (auto simp add: dist_commute lim_sequentially)
  with 0 < ε ball x ε  ball Σ ε = {} have N  n  dist (σ n) x = dist Σ x for n
    by (metis centre_in_ball dist_commute ultrametric_equal_distance_between_ball_ball)
  thus N. nN. dist (σ n) x = dist Σ x by blast
qed



subsection ‹Diameter›

lemma ultrametric_diameter : diameter S = (SUP y  S. dist x y)
  if bounded S and x  S for x :: 'a :: ultrametric_space
proof -
  from x  S have S  {} by blast
  show diameter S = (SUP y  S. dist x y)
  proof (rule order_antisym)
    from diameter_bounded_bound[OF bounded S x  S]
    have y  S  dist x y  diameter S for y .
    thus (SUP y  S. dist x y)  diameter S
      by (rule cSUP_least[OF S  {}])
  next
    have bdd_above (dist x ` S)
      by (meson bdd_above.I2 bounded_any_center bounded S)
    have y  S  z  S  dist y z  max (dist x y) (dist x z) for y z
      by (metis dist_commute ultrametric_dist_triangle)
    also have y  S  z  S 
               max (dist x y) (dist x z)  (SUP y  S. dist x y) for y z
      by (cases dist x y  dist x z)
        (simp_all add: cSUP_upper2[OF bdd_above (dist x ` S)])
    finally have * : y  S  z  S  dist y z  (SUP y  S. dist x y) for y z .
    have (SUP (y, z)  S × S. dist y z)  (SUP y  S. dist x y)
      by (rule cSUP_least) (use "*" in auto simp add: S  {})
    thus diameter S  Sup (dist x ` S)
      by (simp add: diameter_def S  {})
  qed
qed



subsection ‹Totally disconnected›

lemma ultrametric_totally_disconnected :
  x. S = {x} if S  {} connected S
for S :: 'a :: ultrametric_space set
proof -
  from S  {} obtain x where x  S by blast
  have ball x r  S = {}  - ball x r  S = {} if 0 < r for r
    by (rule connected S[unfolded connected_def, simplified, rule_format])
      (simp_all, use order_less_imp_le that ultrametric_closed_ball in blast)
  with x  S have 0 < r  - ball x r  S = {} for r
    by (metis centre_in_ball disjoint_iff)
  hence 0 < r  y  S  dist x y < r for r y
    by (auto simp add: disjoint_iff)
  hence y  S  dist x y = 0 for y
    by (metis dist_self order_less_irrefl zero_less_dist_iff)
  hence y  S  y = x for y by simp
  with x  S show x. S = {x} by blast
qed



(*<*)
end
  (*>*)