Theory Float_Topology

section ‹Topology for Floating Point Numbers›
theory Float_Topology
  imports
    "HOL-Analysis.Multivariate_Analysis"
    "HOL-Library.Float"
begin

text ‹
This topology is totally disconnected and not complete, in which sense is it useful?
Perhaps for convergence of intervals?›

unbundle float.lifting

instantiation float :: dist
begin

lift_definition dist_float :: "float  float  real" is dist .

lemma dist_float_eq_0_iff: "(dist x y = 0) = (x = y)" for x y::float
  by transfer simp

lemma dist_float_triangle2: "dist x y  dist x z + dist y z" for x y z::float
  by transfer (rule dist_triangle2)

instance ..
end

instantiation float :: uniformity
begin

definition uniformity_float :: "(float × float) filter"
  where "uniformity_float = (INF e{0<..}. principal {(x, y). dist x y < e})"

instance ..
end

lemma float_dense_in_real:
  fixes x :: real
  assumes "x < y"
  shows "rfloat. x < r  r < y"
proof -
  from x < y have "0 < y - x" by simp
  with reals_Archimedean obtain q' :: nat where q': "inverse (real q') < y - x" and "0 < q'"
    by blast
  define q::nat where "q  2 ^ nat ¦bitlen q'¦"
  from bitlen_bounds[of q'] 0 < q' have "q' < q"
    by (auto simp: q_def)
  then have "inverse q < inverse q'"
    using 0 < q'
    by (auto simp: divide_simps)
  with q' < q q' have q: "inverse (real q) < y - x" and "0 < q"
    by (auto simp: split: if_splits)
  define p where "p = y * real q - 1"
  define r where "r = of_int p / real q"
  from q have "x < y - inverse (real q)"
    by simp
  also from 0 < q have "y - inverse (real q)  r"
    by (simp add: r_def p_def le_divide_eq left_diff_distrib)
  finally have "x < r" .
  moreover from 0 < q have "r < y"
    by (simp add: r_def p_def divide_less_eq diff_less_eq less_ceiling_iff [symmetric])
  moreover have "r  float"
    by (simp add: r_def q_def)
  ultimately show ?thesis by blast
qed

lemma real_of_float_dense:
  fixes x y :: real
  assumes "x < y"
  shows "q :: float. x < real_of_float q  real_of_float q < y"
  using float_dense_in_real [OF x < y]
  by (auto elim: real_of_float_cases)

instantiation float :: linorder_topology
begin

definition open_float::"float set  bool" where
  "open_float S = (xS. e>0. y. dist y x < e  y  S)"

instance
proof (standard, intro ext iffI)
  fix U::"float set"
  assume "generate_topology (range lessThan  range greaterThan) U"
  then show "open U"
    unfolding open_float_def uniformity_float_def
  proof (induction U)
    case UNIV
    then show ?case by (auto intro!: zero_less_one)
  next
    case (Int a b)
    show ?case
    proof safe
      fix x assume "x  a" "x  b"
      with Int(3,4) obtain e1 e2
        where "dist (y) (x) < e1  y  a"
          and "dist (y) (x) < e2  y  b"
          and "0 < e1" "0 < e2"
        for y
        by (auto dest!: bspec)
      then show "e>0. y. dist y x < e  y  a  b"
        by (auto intro!: exI[where x="min e1 e2"])
    qed
  next
    case (UN K)
    show ?case
    proof safe
      fix x X assume x: "x  X" and X: "X  K"
      from UN[OF X] x obtain e where
        "dist (y) (x) < e  y  X" "e > 0" for y
        by auto
      then show "e>0. y. dist (real_of_float y) (real_of_float x) < e  y  K"
        using x X
        by (auto intro!: exI[where x=e])
    qed
  next
    case (Basis s)
    then show ?case
    proof safe
      fix x u::float
      assume "x < u"
      then show "e>0. y. dist (real_of_float y) (real_of_float x) < e  y  {..<u}"
        by (force simp add: eventually_principal dist_float_def
            dist_real_def abs_real_def
            intro!: exI[where x="(u - x)/2"])
    next
      fix x l::float
      assume "l < x"
      then show "e>0. y. dist (real_of_float y) (real_of_float x) < e  y  {l<..}"
        by (force simp add: eventually_principal dist_float_def
            dist_real_def abs_real_def
            intro!: exI[where x="(x - l)/2"])
    qed
  qed
next
  fix U::"float set"
  assume "open U"
  then obtain e where e:
    "x  U  e x > 0"
    "x  U  dist ( y) ( x) < e x  y  U" for x y
    unfolding open_float_def uniformity_float_def
    by metis
  {
    fix x
    assume x: "x  U"
    obtain e' where e': "e' > 0" "real_of_float e' < e x"
      using real_of_float_dense[of 0 "e x"]
      using e(1)[OF x]
      by auto
    then have "dist (y) ( x) < e'  y  U" for y
      by (intro e[OF x]) auto
    then have "e'>0. y. dist (y) ( x) < real_of_float e'  y  U"
      using e'
      by auto
  } then
  obtain e' where e':
    "x  U  0 < e' x"
    "x  U  dist y x < real_of_float (e' x)  y  U" for x y
    by metis
  then have "U = (xU. greaterThan (x - e' x)  lessThan (x + e' x))"
    by (auto simp: dist_float_def dist_commute dist_real_def)
  also have "generate_topology (range lessThan  range greaterThan) "
    by (intro generate_topology_Union generate_topology.Int generate_topology.Basis) auto
  finally show "generate_topology (range lessThan  range greaterThan) U" .
qed

end

instance float :: metric_space
proof standard
  fix U::"float set"
  show "open U = (xU. F (x', y) in uniformity. x' = x  y  U)"
    unfolding open_float_def open_dist uniformity_float_def uniformity_real_def
  proof safe
    fix x
    assume "xU. e>0. y. dist (real_of_float y) (real_of_float x) < e  y  U" "x  U"
    then obtain e where "e > 0" "dist (y) (x) < e  y  U" for y
      by auto
    then show "F (x', y) in INF e{0<..}. principal {(x, y). dist x y < e}. x' = x  y  U"
      by (intro eventually_INF1[where i=e])
        (auto simp: eventually_principal dist_commute dist_float_def)
  next
    fix u
    assume "xU. F (x', y) in INF e{0<..}. principal {(x, y). dist x y < e}. x' = x  y  U"
      "u  U"
    from this obtain E where E: "E  {0<..}" "finite E"
      "(x', y)xE. {(y', y). dist y' y < x}. x' = u  y  U"
      by (subst (asm) eventually_INF) (auto simp: INF_principal_finite eventually_principal)
    then show "e>0. y. dist (real_of_float y) (real_of_float u) < e  y  U"
      by (intro exI[where x="if E = {} then 1 else Min E"])
        (auto simp: dist_commute dist_float_def)
  qed
qed (use dist_float_eq_0_iff dist_float_triangle2 in
    auto simp add: uniformity_float_def dist_float_def)

instance float::topological_ab_group_add
proof
  fix a b::float
  show "((λx. fst x + snd x)  a + b) (nhds a ×F nhds b)"
  proof (rule tendstoI)
    fix e::real
    assume "e > 0"
    have 1: "(fst  a) (nhds a ×F nhds b)"
      and 2: "(snd  b) (nhds a ×F nhds b)"
      by (auto intro!: tendsto_eq_intros filterlim_ident simp: nhds_prod[symmetric])
    have "F x in nhds a ×F nhds b. dist (fst x) (a) < e/2"
      by (rule tendstoD[OF 1]) (use e > 0 in auto)
    moreover have "F x in nhds a ×F nhds b. dist (snd x) (b) < e/2"
      by (rule tendstoD[OF 2]) (use e > 0 in auto)
    ultimately show "F x in nhds a ×F nhds b. dist (fst x + snd x) (a + b) < e"
    proof eventually_elim
      case (elim x)
      then show ?case
        by (auto simp: dist_float_def) norm
    qed
  qed
  show "(uminus  - a) (nhds a)"
    using filterlim_ident[of "nhds a"]
    by (auto intro!: tendstoI dest!: tendstoD simp: dist_float_def dist_minus)
qed

lifting_update float.lifting
lifting_forget float.lifting

end