/- Copyright (c) 2015 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Robert Lewis Metric spaces. -/ import data.real.complete data.pnat ..topology.continuous ..topology.limit data.set open nat real eq.ops classical set prod set.filter topology interval structure metric_space [class] (M : Type) : Type := (dist : M → M → ℝ) (dist_self : ∀ x : M, dist x x = 0) (eq_of_dist_eq_zero : ∀ {x y : M}, dist x y = 0 → x = y) (dist_comm : ∀ x y : M, dist x y = dist y x) (dist_triangle : ∀ x y z : M, dist x z ≤ dist x y + dist y z) namespace analysis section metric_space_M variables {M : Type} [metric_space M] definition dist (x y : M) : ℝ := metric_space.dist x y proposition dist_self (x : M) : dist x x = 0 := metric_space.dist_self x proposition eq_of_dist_eq_zero {x y : M} (H : dist x y = 0) : x = y := metric_space.eq_of_dist_eq_zero H proposition dist_comm (x y : M) : dist x y = dist y x := metric_space.dist_comm x y proposition dist_eq_zero_iff (x y : M) : dist x y = 0 ↔ x = y := iff.intro eq_of_dist_eq_zero (suppose x = y, this ▸ !dist_self) proposition dist_triangle (x y z : M) : dist x z ≤ dist x y + dist y z := metric_space.dist_triangle x y z proposition dist_nonneg (x y : M) : 0 ≤ dist x y := have dist x y + dist y x ≥ 0, by rewrite -(dist_self x); apply dist_triangle, have 2 * dist x y ≥ 0, by krewrite [-real.one_add_one, right_distrib, +one_mul, dist_comm at {2}]; apply this, nonneg_of_mul_nonneg_left this two_pos proposition dist_pos_of_ne {x y : M} (H : x ≠ y) : dist x y > 0 := lt_of_le_of_ne !dist_nonneg (suppose 0 = dist x y, H (iff.mp !dist_eq_zero_iff this⁻¹)) proposition ne_of_dist_pos {x y : M} (H : dist x y > 0) : x ≠ y := suppose x = y, have H1 : dist x x > 0, by rewrite this at {2}; exact H, by rewrite dist_self at H1; apply not_lt_self _ H1 proposition eq_of_forall_dist_le {x y : M} (H : ∀ ε, ε > 0 → dist x y ≤ ε) : x = y := eq_of_dist_eq_zero (eq_zero_of_nonneg_of_forall_le !dist_nonneg H) /- instantiate metric space as a topology -/ definition open_ball (x : M) (ε : ℝ) := {y | dist y x < ε} theorem open_ball_eq_empty_of_nonpos (x : M) {ε : ℝ} (Hε : ε ≤ 0) : open_ball x ε = ∅ := begin apply eq_empty_of_forall_not_mem, intro y Hlt, apply not_lt_of_ge (dist_nonneg y x), apply lt_of_lt_of_le Hlt Hε end theorem pos_of_mem_open_ball {x : M} {ε : ℝ} {u : M} (Hu : u ∈ open_ball x ε) : ε > 0 := begin apply lt_of_not_ge, intro Hge, note Hop := open_ball_eq_empty_of_nonpos x Hge, rewrite Hop at Hu, apply not_mem_empty _ Hu end theorem mem_open_ball (x : M) {ε : ℝ} (H : ε > 0) : x ∈ open_ball x ε := show dist x x < ε, by rewrite dist_self; assumption definition closed_ball (x : M) (ε : ℝ) := {y | dist y x ≤ ε} theorem closed_ball_eq_compl (x : M) (ε : ℝ) : closed_ball x ε = - {y | dist y x > ε} := ext (take y, iff.intro (suppose dist y x ≤ ε, not_lt_of_ge this) (suppose ¬ dist y x > ε, le_of_not_gt this)) variable (M) definition open_sets_basis : set (set M) := { s | ∃ x, ∃ ε, s = open_ball x ε } definition metric_topology [instance] : topology M := topology.generated_by (open_sets_basis M) variable {M} theorem open_ball_mem_open_sets_basis (x : M) (ε : ℝ) : open_ball x ε ∈ open_sets_basis M := exists.intro x (exists.intro ε rfl) theorem Open_open_ball (x : M) (ε : ℝ) : Open (open_ball x ε) := by apply generators_mem_topology_generated_by; apply open_ball_mem_open_sets_basis theorem closed_closed_ball (x : M) {ε : ℝ} (H : ε > 0) : closed (closed_ball x ε) := Open_of_forall_exists_Open_nbhd (take y, suppose ¬ dist y x ≤ ε, have dist y x > ε, from lt_of_not_ge this, let B := open_ball y (dist y x - ε) in have y ∈ B, from mem_open_ball y (sub_pos_of_lt this), have B ⊆ - closed_ball x ε, from take y', assume Hy'y : dist y' y < dist y x - ε, assume Hy'x : dist y' x ≤ ε, show false, from not_lt_self (dist y x) (calc dist y x ≤ dist y y' + dist y' x : dist_triangle ... < dist y x - ε + dist y' x : by rewrite dist_comm; apply add_lt_add_right Hy'y ... ≤ dist y x - ε + ε : add_le_add_left Hy'x ... = dist y x : by rewrite [sub_add_cancel]), exists.intro B (and.intro (Open_open_ball _ _) (and.intro `y ∈ B` this))) proposition open_ball_subset_open_ball_of_le (x : M) {r₁ r₂ : ℝ} (H : r₁ ≤ r₂) : open_ball x r₁ ⊆ open_ball x r₂ := take y, assume ymem, lt_of_lt_of_le ymem H theorem exists_open_ball_subset_of_Open_of_mem {U : set M} (HU : Open U) {x : M} (Hx : x ∈ U) : ∃ (r : ℝ), r > 0 ∧ open_ball x r ⊆ U := begin induction HU with s sbasis s t sbasis tbasis ihs iht S Sbasis ihS, {cases sbasis with x' aux, cases aux with ε seq, have x ∈ open_ball x' ε, by rewrite -seq; exact Hx, have εpos : ε > 0, from pos_of_mem_open_ball this, have ε - dist x x' > 0, from sub_pos_of_lt `x ∈ open_ball x' ε`, existsi (ε - dist x x'), split, exact this, rewrite seq, show open_ball x (ε - dist x x') ⊆ open_ball x' ε, from take y, suppose dist y x < ε - dist x x', calc dist y x' ≤ dist y x + dist x x' : dist_triangle ... < ε - dist x x' + dist x x' : add_lt_add_right this ... = ε : sub_add_cancel}, {existsi 1, split, exact zero_lt_one, exact subset_univ _}, {cases ihs (and.left Hx) with rs aux, cases aux with rspos ballrs_sub, cases iht (and.right Hx) with rt aux, cases aux with rtpos ballrt_sub, let rmin := min rs rt, existsi rmin, split, exact lt_min rspos rtpos, have open_ball x rmin ⊆ s, from subset.trans (open_ball_subset_open_ball_of_le x !min_le_left) ballrs_sub, have open_ball x rmin ⊆ t, from subset.trans (open_ball_subset_open_ball_of_le x !min_le_right) ballrt_sub, show open_ball x (min rs rt) ⊆ s ∩ t, by apply subset_inter; repeat assumption}, cases Hx with s aux, cases aux with sS xs, cases (ihS sS xs) with r aux, cases aux with rpos ballr_sub, existsi r, split, exact rpos, show open_ball x r ⊆ ⋃₀ S, from subset.trans ballr_sub (subset_sUnion_of_mem sS) end /- limits in metric spaces -/ proposition eventually_nhds_intro {P : M → Prop} {ε : ℝ} (εpos : ε > 0) {x : M} (H : ∀ x', dist x' x < ε → P x') : eventually P (nhds x) := topology.eventually_nhds_intro (Open_open_ball x ε) (mem_open_ball x εpos) H proposition eventually_nhds_dest {P : M → Prop} {x : M} (H : eventually P (nhds x)) : ∃ ε, ε > 0 ∧ ∀ x', dist x' x < ε → P x' := obtain s [(Os : Open s) [(xs : x ∈ s) (Hs : ∀₀ x' ∈ s, P x')]], from topology.eventually_nhds_dest H, obtain ε [(εpos : ε > 0) (Hε : open_ball x ε ⊆ s)], from exists_open_ball_subset_of_Open_of_mem Os xs, exists.intro ε (and.intro εpos (take x', suppose dist x' x < ε, have x' ∈ s, from Hε this, show P x', from Hs this)) proposition eventually_nhds_iff (P : M → Prop) (x : M) : eventually P (nhds x) ↔ (∃ ε, ε > 0 ∧ ∀ x', dist x' x < ε → P x') := iff.intro eventually_nhds_dest (assume H, obtain ε [εpos Hε], from H, eventually_nhds_intro εpos Hε) proposition eventually_dist_lt_nhds (x : M) {ε : ℝ} (εpos : ε > 0) : eventually (λ x', dist x' x < ε) (nhds x) := eventually_nhds_intro εpos (λ x' H, H) proposition eventually_at_within_intro {P : M → Prop} {ε : ℝ} (εpos : ε > 0) {x : M} {s : set M} (H : ∀₀ x' ∈ s, dist x' x < ε → x' ≠ x → P x') : eventually P [at x within s] := topology.eventually_at_within_intro (Open_open_ball x ε) (mem_open_ball x εpos) (λ x' x'mem x'ne x's, H x's x'mem x'ne) proposition eventually_at_within_dest {P : M → Prop} {x : M} {s : set M} (H : eventually P [at x within s]) : ∃ ε, ε > 0 ∧ ∀₀ x' ∈ s, dist x' x < ε → x' ≠ x → P x' := obtain t [(Ot : Open t) [(xt : x ∈ t) (Ht : ∀₀ x' ∈ t, x' ≠ x → x' ∈ s → P x')]], from topology.eventually_at_within_dest H, obtain ε [(εpos : ε > 0) (Hε : open_ball x ε ⊆ t)], from exists_open_ball_subset_of_Open_of_mem Ot xt, exists.intro ε (and.intro εpos (take x', assume x's distx'x x'nex, have x' ∈ t, from Hε distx'x, show P x', from Ht this x'nex x's)) proposition eventually_at_within_iff (P : M → Prop) (x : M) (s : set M) : eventually P [at x within s] ↔ ∃ ε, ε > 0 ∧ ∀₀ x' ∈ s, dist x' x < ε → x' ≠ x → P x' := iff.intro eventually_at_within_dest (λ H, obtain ε [εpos Hε], from H, eventually_at_within_intro εpos Hε) proposition eventually_at_intro {P : M → Prop} {ε : ℝ} (εpos : ε > 0) {x : M} (H : ∀ x', dist x' x < ε → x' ≠ x → P x') : eventually P [at x] := topology.eventually_at_intro (Open_open_ball x ε) (mem_open_ball x εpos) (λ x' x'mem x'ne, H x' x'mem x'ne) proposition eventually_at_dest {P : M → Prop} {x : M} (H : eventually P [at x]) : ∃ ε, ε > 0 ∧ ∀ ⦃x'⦄, dist x' x < ε → x' ≠ x → P x' := obtain ε [εpos Hε], from eventually_at_within_dest H, exists.intro ε (and.intro εpos (λ x', Hε x' (mem_univ x'))) proposition eventually_at_iff (P : M → Prop) (x : M) : eventually P [at x] ↔ ∃ ε, ε > 0 ∧ ∀ ⦃x'⦄, dist x' x < ε → x' ≠ x → P x' := iff.intro eventually_at_dest (λ H, obtain ε [εpos Hε], from H, eventually_at_intro εpos Hε) section approaches variables {X : Type} {F : filter X} {f : X → M} {y : M} proposition approaches_intro (H : ∀ ε, ε > 0 → eventually (λ x, dist (f x) y < ε) F) : (f ⟶ y) F := tendsto_intro (take P, assume eventuallyP, obtain ε [(εpos : ε > 0) (Hε : ∀ x', dist x' y < ε → P x')], from eventually_nhds_dest eventuallyP, show eventually (λ x, P (f x)) F, from eventually_mono (H ε εpos) (λ x Hx, Hε (f x) Hx)) proposition approaches_dest (H : (f ⟶ y) F) {ε : ℝ} (εpos : ε > 0) : eventually (λ x, dist (f x) y < ε) F := tendsto_dest H (eventually_dist_lt_nhds y εpos) variables (F f y) proposition approaches_iff : (f ⟶ y) F ↔ (∀ ε, ε > 0 → eventually (λ x, dist (f x) y < ε) F) := iff.intro approaches_dest approaches_intro -- TODO: prove this in greater generality in topology.limit proposition approaches_constant : ((λ x, y) ⟶ y) F := approaches_intro (λ ε εpos, eventually_of_forall F (λ x, show dist y y < ε, by rewrite dist_self; apply εpos)) end approaches -- here we full unwrap two particular kinds of convergence3 proposition approaches_at_infty_intro {f : ℕ → M} {y : M} (H : ∀ ε, ε > 0 → ∃ N, ∀ n, n ≥ N → dist (f n) y < ε) : f ⟶ y [at ∞] := approaches_intro (λ ε εpos, obtain N HN, from H ε εpos, eventually_at_infty_intro HN) proposition approaches_at_infty_dest {f : ℕ → M} {y : M} (H : f ⟶ y [at ∞]) ⦃ε : ℝ⦄ (εpos : ε > 0) : ∃ N, ∀ ⦃n⦄, n ≥ N → dist (f n) y < ε := have eventually (λ x, dist (f x) y < ε) [at ∞], from approaches_dest H εpos, eventually_at_infty_dest this proposition approaches_at_infty_iff (f : ℕ → M) (y : M) : f ⟶ y [at ∞] ↔ (∀ ε, ε > 0 → ∃ N, ∀ ⦃n⦄, n ≥ N → dist (f n) y < ε) := iff.intro approaches_at_infty_dest approaches_at_infty_intro section metric_space_N variables {N : Type} [metric_space N] proposition approaches_at_dest {f : M → N} {y : N} {x : M} (H : f ⟶ y [at x]) ⦃ε : ℝ⦄ (εpos : ε > 0) : ∃ δ, δ > 0 ∧ ∀ ⦃x'⦄, dist x' x < δ → x' ≠ x → dist (f x') y < ε := have eventually (λ x, dist (f x) y < ε) [at x], from approaches_dest H εpos, eventually_at_dest this proposition approaches_at_intro {f : M → N} {y : N} {x : M} (H : ∀ ε, ε > 0 → ∃ δ, δ > 0 ∧ ∀ ⦃x'⦄, dist x' x < δ → x' ≠ x → dist (f x') y < ε) : f ⟶ y [at x] := approaches_intro (λ ε εpos, obtain δ [δpos Hδ], from H ε εpos, eventually_at_intro δpos Hδ) proposition approaches_at_iff (f : M → N) (y : N) (x : M) : f ⟶ y [at x] ↔ (∀ ⦃ε⦄, ε > 0 → ∃ δ, δ > 0 ∧ ∀ ⦃x'⦄, dist x' x < δ → x' ≠ x → dist (f x') y < ε) := iff.intro approaches_at_dest approaches_at_intro end metric_space_N -- TODO: remove this. It is only here temporarily, because it is used in normed_space abbreviation converges_seq [class] (X : ℕ → M) : Prop := ∃ y, X ⟶ y [at ∞] -- TODO: refactor -- the same, with ≤ in place of <; easier to prove, harder to use definition approaches_at_infty_intro' {X : ℕ → M} {y : M} (H : ∀ ⦃ε : ℝ⦄, ε > 0 → ∃ N : ℕ, ∀ {n}, n ≥ N → dist (X n) y ≤ ε) : (X ⟶ y) [at ∞] := approaches_at_infty_intro take ε, assume epos : ε > 0, have e2pos : ε / 2 > 0, from div_pos_of_pos_of_pos `ε > 0` two_pos, obtain N HN, from H e2pos, exists.intro N (take n, suppose n ≥ N, calc dist (X n) y ≤ ε / 2 : HN _ `n ≥ N` ... < ε : div_two_lt_of_pos epos) -- TODO: prove more generally proposition approaches_at_infty_unique {X : ℕ → M} {y₁ y₂ : M} (H₁ : X ⟶ y₁ [at ∞]) (H₂ : X ⟶ y₂ [at ∞]) : y₁ = y₂ := eq_of_forall_dist_le (take ε, suppose ε > 0, have e2pos : ε / 2 > 0, from div_pos_of_pos_of_pos `ε > 0` two_pos, obtain N₁ (HN₁ : ∀ {n}, n ≥ N₁ → dist (X n) y₁ < ε / 2), from approaches_at_infty_dest H₁ e2pos, obtain N₂ (HN₂ : ∀ {n}, n ≥ N₂ → dist (X n) y₂ < ε / 2), from approaches_at_infty_dest H₂ e2pos, let N := max N₁ N₂ in have dN₁ : dist (X N) y₁ < ε / 2, from HN₁ !le_max_left, have dN₂ : dist (X N) y₂ < ε / 2, from HN₂ !le_max_right, have dist y₁ y₂ < ε, from calc dist y₁ y₂ ≤ dist y₁ (X N) + dist (X N) y₂ : dist_triangle ... = dist (X N) y₁ + dist (X N) y₂ : dist_comm ... < ε / 2 + ε / 2 : add_lt_add dN₁ dN₂ ... = ε : add_halves, show dist y₁ y₂ ≤ ε, from le_of_lt this) /- TODO: revise definition converges_seq [class] (X : ℕ → M) : Prop := ∃ y, X ⟶ y in ℕ noncomputable definition limit_seq (X : ℕ → M) [H : converges_seq X] : M := some H proposition converges_to_limit_seq (X : ℕ → M) [H : converges_seq X] : (X ⟶ limit_seq X in ℕ) := some_spec H proposition eq_limit_of_converges_to_seq {X : ℕ → M} {y : M} (H : X ⟶ y in ℕ) : y = @limit_seq M _ X (exists.intro y H) := converges_to_seq_unique H (@converges_to_limit_seq M _ X (exists.intro y H)) proposition converges_to_seq_offset_left {X : ℕ → M} {y : M} (k : ℕ) (H : X ⟶ y in ℕ) : (λ n, X (k + n)) ⟶ y in ℕ := have aux : (λ n, X (k + n)) = (λ n, X (n + k)), from funext (take n, by rewrite add.comm), by rewrite aux; exact converges_to_seq_offset k H proposition converges_to_seq_of_converges_to_seq_offset_left {X : ℕ → M} {y : M} {k : ℕ} (H : (λ n, X (k + n)) ⟶ y in ℕ) : X ⟶ y in ℕ := have aux : (λ n, X (k + n)) = (λ n, X (n + k)), from funext (take n, by rewrite add.comm), by rewrite aux at H; exact converges_to_seq_of_converges_to_seq_offset H -/ proposition bounded_of_converges_seq {X : ℕ → M} {x : M} (H : X ⟶ x [at ∞]) : ∃ K : ℝ, ∀ n : ℕ, dist (X n) x ≤ K := have eventually (λ n, dist (X n) x < 1) [at ∞], from approaches_dest H zero_lt_one, obtain N (HN : ∀ n, n ≥ N → dist (X n) x < 1), from eventually_at_infty_dest this, let K := max 1 (Max i ∈ '(-∞, N), dist (X i) x) in exists.intro K (take n, if Hn : n < N then show dist (X n) x ≤ K, from le.trans (le_Max _ Hn) !le_max_right else show dist (X n) x ≤ K, from le.trans (le_of_lt (HN n (le_of_not_gt Hn))) !le_max_left) /- cauchy sequences -/ definition cauchy (X : ℕ → M) : Prop := ∀ ε : ℝ, ε > 0 → ∃ N, ∀ m n, m ≥ N → n ≥ N → dist (X m) (X n) < ε proposition cauchy_of_converges_seq {X : ℕ → M} (H : ∃ y, X ⟶ y [at ∞]) : cauchy X := take ε, suppose ε > 0, obtain y (Hy : X ⟶ y [at ∞]), from H, have e2pos : ε / 2 > 0, from div_pos_of_pos_of_pos `ε > 0` two_pos, have eventually (λ n, dist (X n) y < ε / 2) [at ∞], from approaches_dest Hy e2pos, obtain N (HN : ∀ {n}, n ≥ N → dist (X n) y < ε / 2), from eventually_at_infty_dest this, exists.intro N (take m n, suppose m ≥ N, suppose n ≥ N, have dN₁ : dist (X m) y < ε / 2, from HN `m ≥ N`, have dN₂ : dist (X n) y < ε / 2, from HN `n ≥ N`, show dist (X m) (X n) < ε, from calc dist (X m) (X n) ≤ dist (X m) y + dist y (X n) : dist_triangle ... = dist (X m) y + dist (X n) y : dist_comm ... < ε / 2 + ε / 2 : add_lt_add dN₁ dN₂ ... = ε : add_halves) end metric_space_M /- convergence of a function at a point -/ section metric_space_M_N variables {M N : Type} [metric_space M] [metric_space N] /- definition converges_to_at (f : M → N) (y : N) (x : M) := ∀ ⦃ε⦄, ε > 0 → ∃ δ, δ > 0 ∧ ∀ ⦃x'⦄, x' ≠ x ∧ dist x' x < δ → dist (f x') y < ε notation f `⟶` y `at` x := converges_to_at f y x definition converges_at [class] (f : M → N) (x : M) := ∃ y, converges_to_at f y x noncomputable definition limit_at (f : M → N) (x : M) [H : converges_at f x] : N := some H proposition converges_to_limit_at (f : M → N) (x : M) [H : converges_at f x] : (f ⟶ limit_at f x at x) := some_spec H -/ -- TODO: refactor section open pnat rat private lemma of_rat_rat_of_pnat_eq_of_nat_nat_of_pnat (p : pnat) : of_rat (rat_of_pnat p) = of_nat (nat_of_pnat p) := rfl theorem cnv_real_of_cnv_nat {X : ℕ → M} {c : M} (H : ∀ n : ℕ, dist (X n) c < 1 / (real.of_nat n + 1)) : ∀ ε : ℝ, ε > 0 → ∃ N : ℕ, ∀ n : ℕ, n ≥ N → dist (X n) c < ε := begin intros ε Hε, cases ex_rat_pos_lower_bound_of_pos Hε with q Hq, cases Hq with Hq1 Hq2, cases pnat_bound Hq1 with p Hp, existsi pnat.nat_of_pnat p, intros n Hn, apply lt_of_lt_of_le, apply H, apply le.trans, rotate 1, apply Hq2, have Hrat : of_rat (inv p) ≤ of_rat q, from of_rat_le_of_rat_of_le Hp, apply le.trans, rotate 1, exact Hrat, change 1 / (of_nat n + 1) ≤ of_rat ((1 : ℚ) / (rat_of_pnat p)), rewrite [of_rat_divide, of_rat_one], eapply one_div_le_one_div_of_le, krewrite -of_rat_zero, apply of_rat_lt_of_rat_of_lt, apply rat_of_pnat_is_pos, krewrite [of_rat_rat_of_pnat_eq_of_nat_nat_of_pnat, -real.of_nat_add], apply real.of_nat_le_of_nat_of_le, apply le_add_of_le_right, assumption end end -- a nice illustration of the limit library: [at c] and [at ∞] can be replaced by any filters theorem comp_approaches_at_infty {f : M → N} {c : M} {l : N} (Hf : f ⟶ l [at c]) {X : ℕ → M} (HX₁ : X ⟶ c [at ∞]) (HX₂ : eventually (λ n, X n ≠ c) [at ∞]) : (λ n, f (X n)) ⟶ l [at ∞] := tendsto_comp_of_approaches_of_tendsto_at HX₁ HX₂ Hf -- TODO: refactor theorem converges_to_at_of_all_conv_seqs {f : M → N} (c : M) (l : N) (Hseq : ∀ X : ℕ → M, ((∀ n : ℕ, ((X n) ≠ c) ∧ (X ⟶ c [at ∞])) → ((λ n : ℕ, f (X n)) ⟶ l [at ∞]))) : f ⟶ l [at c] := by_contradiction (assume Hnot : ¬ (f ⟶ l [at c]), obtain ε Hε, from exists_not_of_not_forall (λ H, Hnot (approaches_at_intro H)), let Hε' := and_not_of_not_implies Hε in obtain (H1 : ε > 0) H2, from Hε', have H3 : ∀ δ : ℝ, (δ > 0 → ∃ x' : M, x' ≠ c ∧ dist x' c < δ ∧ dist (f x') l ≥ ε), begin -- tedious!! intros δ Hδ, note Hε'' := forall_not_of_not_exists H2, note H4 := forall_not_of_not_exists H2 δ, have ¬ (∀ x' : M, dist x' c < δ → x' ≠ c → dist (f x') l < ε), from λ H', H4 (and.intro Hδ H'), note H5 := exists_not_of_not_forall this, cases H5 with x' Hx', existsi x', note H6 := and_not_of_not_implies Hx', -- rewrite and.assoc at H6, cases H6 with H6a H6b, split, cases (and_not_of_not_implies H6b), assumption, split, assumption, apply le_of_not_gt, cases (and_not_of_not_implies H6b), assumption end, let S : ℕ → M → Prop := λ n x, 0 < dist x c ∧ dist x c < 1 / (of_nat n + 1) ∧ dist (f x) l ≥ ε in have HS : ∀ n : ℕ, ∃ m : M, S n m, begin intro k, have Hpos : 0 < of_nat k + 1, from of_nat_succ_pos k, cases H3 (1 / (k + 1)) (one_div_pos_of_pos Hpos) with x' Hx', cases Hx' with Hne Hx', cases Hx' with Hdistl Hdistg, existsi x', esimp, split, apply dist_pos_of_ne, assumption, split, repeat assumption end, let X : ℕ → M := λ n, some (HS n) in have H4 : ∀ n : ℕ, ((X n) ≠ c) ∧ (X ⟶ c [at ∞]), from (take n, and.intro (begin note Hspec := some_spec (HS n), esimp, esimp at Hspec, cases Hspec, apply ne_of_dist_pos, assumption end) (begin apply approaches_at_infty_intro, apply cnv_real_of_cnv_nat, intro m, note Hspec := some_spec (HS m), esimp, esimp at Hspec, cases Hspec with Hspec1 Hspec2, cases Hspec2, assumption end)), have H5 : (λ n : ℕ, f (X n)) ⟶ l [at ∞], from Hseq X H4, begin note H6 := approaches_at_infty_dest H5 H1, cases H6 with Q HQ, note HQ' := HQ !le.refl, esimp at HQ', apply absurd HQ', apply not_lt_of_ge, note H7 := some_spec (HS Q), esimp at H7, cases H7 with H71 H72, cases H72, assumption end) end metric_space_M_N section continuity variables {M N : Type} [Hm : metric_space M] [Hn : metric_space N] include Hm Hn open topology set /- continuity at a point -/ -- the ε - δ definition of continuity is equivalent to the topological definition theorem continuous_at_intro {f : M → N} {x : M} (H : ∀ ⦃ε⦄, ε > 0 → ∃ δ, δ > 0 ∧ ∀ ⦃x'⦄, dist x' x < δ → dist (f x') (f x) < ε) : continuous_at f x := begin rewrite ↑continuous_at, intros U Uopen HfU, cases exists_open_ball_subset_of_Open_of_mem Uopen HfU with r Hr, cases Hr with Hr HUr, cases H Hr with δ Hδ, cases Hδ with Hδ Hx'δ, existsi open_ball x δ, split, apply Open_open_ball, split, apply mem_open_ball, exact Hδ, intro y Hy, apply mem_preimage, apply HUr, note Hy'' := Hx'δ Hy, exact Hy'' end theorem continuous_at_elim {f : M → N} {x : M} (Hfx : continuous_at f x) : ∀ ⦃ε⦄, ε > 0 → ∃ δ, δ > 0 ∧ ∀ ⦃x'⦄, dist x' x < δ → dist (f x') (f x) < ε := begin intros ε Hε, rewrite [↑continuous_at at Hfx], cases @Hfx (open_ball (f x) ε) !Open_open_ball (mem_open_ball _ Hε) with V HV, cases HV with HV HVx, cases HVx with HVx HVf, cases exists_open_ball_subset_of_Open_of_mem HV HVx with δ Hδ, cases Hδ with Hδ Hδx, existsi δ, split, exact Hδ, intro x' Hx', apply HVf, apply Hδx, apply Hx', end theorem continuous_at_of_converges_to_at {f : M → N} {x : M} (Hf : f ⟶ f x [at x]) : continuous_at f x := continuous_at_intro (take ε, suppose ε > 0, obtain δ Hδ, from approaches_at_dest Hf this, exists.intro δ (and.intro (and.left Hδ) (take x', suppose dist x' x < δ, if Heq : x' = x then by rewrite [-Heq, dist_self]; assumption else (suffices dist x' x < δ, from and.right Hδ x' this Heq, this)))) theorem converges_to_at_of_continuous_at {f : M → N} {x : M} (Hf : continuous_at f x) : f ⟶ f x [at x] := approaches_at_intro (take ε, suppose ε > 0, obtain δ [δpos Hδ], from continuous_at_elim Hf this, exists.intro δ (and.intro δpos (λ x' Hx' xnex', Hδ x' Hx'))) definition continuous (f : M → N) : Prop := ∀ x, continuous_at f x theorem converges_seq_comp_of_converges_seq_of_cts (X : ℕ → M) [HX : converges_seq X] {f : M → N} (Hf : continuous f) : converges_seq (λ n, f (X n)) := begin cases HX with xlim Hxlim, existsi f xlim, apply approaches_at_infty_intro, intros ε Hε, let Hcont := (continuous_at_elim (Hf xlim)) Hε, cases Hcont with δ Hδ, cases approaches_at_infty_dest Hxlim (and.left Hδ) with B HB, existsi B, intro n Hn, apply and.right Hδ, apply HB Hn end omit Hn theorem id_continuous : continuous (λ x : M, x) := begin intros x, apply continuous_at_intro, intro ε Hε, existsi ε, split, assumption, intros, assumption end end continuity end analysis /- complete metric spaces -/ structure complete_metric_space [class] (M : Type) extends metricM : metric_space M : Type := (complete : ∀ X, @analysis.cauchy M metricM X → @analysis.converges_seq M metricM X) namespace analysis proposition complete (M : Type) [cmM : complete_metric_space M] {X : ℕ → M} (H : cauchy X) : converges_seq X := complete_metric_space.complete X H end analysis /- the reals form a metric space -/ noncomputable definition metric_space_real [instance] : metric_space ℝ := ⦃ metric_space, dist := λ x y, abs (x - y), dist_self := λ x, abstract by rewrite [sub_self, abs_zero] end, eq_of_dist_eq_zero := λ x y, eq_of_abs_sub_eq_zero, dist_comm := abs_sub, dist_triangle := abs_sub_le ⦄