Theory HOL-Analysis.Sparse_In

theory Sparse_In 
  imports Homotopy

begin

(*TODO: can we remove the definition isolated_points_of from 
  HOL-Complex_Analysis.Complex_Singularities?*)
(*TODO: more lemmas between sparse_in and discrete?*)

subsection ‹A set of points sparse in another set›

definition sparse_in:: "'a :: topological_space set  'a set  bool"
    (infixl "(sparse'_in)" 50)
  where
  "pts sparse_in A = (xA. B. xB  open B  (yB. ¬ y islimpt pts))"

lemma sparse_in_empty[simp]: "{} sparse_in A"
  by (meson UNIV_I empty_iff islimpt_def open_UNIV sparse_in_def)

lemma finite_imp_sparse:
  fixes pts::"'a:: t1_space set"
  shows "finite pts  pts sparse_in S"
  by (meson UNIV_I islimpt_finite open_UNIV sparse_in_def)

lemma sparse_in_singleton[simp]: "{x} sparse_in (A::'a:: t1_space set)"
  by (rule finite_imp_sparse) auto

lemma sparse_in_ball_def:
  "pts sparse_in D  (xD. e>0. yball x e. ¬ y islimpt pts)"
  unfolding sparse_in_def
  by (meson Elementary_Metric_Spaces.open_ball open_contains_ball_eq subset_eq)

lemma get_sparse_in_cover:
  assumes "pts sparse_in A"
  obtains B where "open B" "A  B" "yB. ¬ y islimpt pts"
proof -
  obtain getB where getB:"xgetB x" "open (getB x)" "ygetB x. ¬ y islimpt pts"
    if "xA" for x
    using assms(1) unfolding sparse_in_def by metis
  define B where "B = Union (getB ` A)"
  have "open B" unfolding B_def using getB(2) by blast
  moreover have "A  B" unfolding B_def using getB(1) by auto
  moreover have "yB. ¬ y islimpt pts" unfolding B_def by (meson UN_iff getB(3))
  ultimately show ?thesis using that by blast
qed

lemma sparse_in_open:
  assumes "open A"
  shows "pts sparse_in A  (yA. ¬y islimpt pts)"
  using assms unfolding sparse_in_def by auto

lemma sparse_in_not_in:
  assumes "pts sparse_in A" "xA"
  obtains B where "open B" "xB" "yB. yx  ypts"
  using assms unfolding sparse_in_def
  by (metis islimptI)

lemma sparse_in_subset:
  assumes "pts sparse_in A" "B  A"
  shows "pts sparse_in B"
  using assms unfolding sparse_in_def  by auto

lemma sparse_in_subset2:
  assumes "pts1 sparse_in D" "pts2  pts1"
  shows "pts2 sparse_in D"
  by (meson assms(1) assms(2) islimpt_subset sparse_in_def)

lemma sparse_in_union:
  assumes "pts1 sparse_in D1" "pts2 sparse_in D1" 
  shows "(pts1  pts2) sparse_in (D1  D2)" 
  using assms unfolding sparse_in_def islimpt_Un
  by (metis Int_iff open_Int)

lemma sparse_in_compact_finite:
  assumes "pts sparse_in A" "compact A"
  shows "finite (A  pts)"
  apply (rule finite_not_islimpt_in_compact[OF compact A])
  using assms unfolding sparse_in_def by blast

lemma sparse_imp_closedin_pts:
  assumes "pts sparse_in D" 
  shows "closedin (top_of_set D) (D  pts)"
  using assms islimpt_subset unfolding closedin_limpt sparse_in_def 
  by fastforce

lemma open_diff_sparse_pts:
  assumes "open D" "pts sparse_in D" 
  shows "open (D - pts)"
  using assms sparse_imp_closedin_pts
  by (metis Diff_Diff_Int Diff_cancel Diff_eq_empty_iff Diff_subset 
      closedin_def double_diff openin_open_eq topspace_euclidean_subtopology)

lemma sparse_imp_countable:
  fixes D::"'a ::euclidean_space set"
  assumes  "open D" "pts sparse_in D"
  shows "countable (D  pts)"
proof -
  obtain K :: "nat  'a ::euclidean_space set"
      where K: "D = (n. K n)" "n. compact (K n)"
    using assms  by (metis open_Union_compact_subsets)
  then have "D pts = (n. K n  pts)"
    by blast
  moreover have "n. finite (K n  pts)"
    by (metis K(1) K(2) Union_iff assms(2) rangeI 
        sparse_in_compact_finite sparse_in_subset subsetI)
  ultimately show ?thesis
    by (metis countableI_type countable_UN countable_finite)
qed

lemma sparse_imp_connected:
  fixes D::"'a ::euclidean_space set"
  assumes  "2  DIM ('a)"  "connected D" "open D" "pts sparse_in D"
  shows "connected (D - pts)"
  using assms
  by (metis Diff_Compl Diff_Diff_Int Diff_eq connected_open_diff_countable 
      sparse_imp_countable)

lemma sparse_in_eventually_iff:
  assumes "open A"
  shows "pts sparse_in A  (yA. (F y in at y. y  pts))"
  unfolding sparse_in_open[OF open A] islimpt_iff_eventually
  by simp

lemma get_sparse_from_eventually:
  fixes A::"'a::topological_space set"
  assumes "xA. F z in at x. P z" "open A"
  obtains pts where "pts sparse_in A" "xA - pts. P x"
proof -
  define pts::"'a set" where "pts={x. ¬P x}"
  have "pts sparse_in A" "xA - pts. P x"
    unfolding sparse_in_eventually_iff[OF open A] pts_def
    using assms(1) by simp_all
  then show ?thesis using that by blast
qed

lemma sparse_disjoint:
  assumes "pts  A = {}" "open A"
  shows "pts sparse_in A"
  using assms unfolding sparse_in_eventually_iff[OF open A]
      eventually_at_topological
  by blast


subsection ‹Co-sparseness filter›

text ‹
  The co-sparseness filter allows us to talk about properties that hold on a given set except
  for an ``insignificant'' number of points that are sparse in that set.
›
lemma is_filter_cosparse: "is_filter (λP. {x. ¬P x} sparse_in A)"
proof (standard, goal_cases)
  case 1
  thus ?case by auto
next
  case (2 P Q)
  from sparse_in_union[OF this, of UNIV] show ?case
    by (auto simp: Un_def)
next
  case (3 P Q)
  from 3(2) show ?case
    by (rule sparse_in_subset2) (use 3(1) in auto)
qed  

definition cosparse :: "'a set  'a :: topological_space filter" where
 "cosparse A = Abs_filter (λP. {x. ¬P x} sparse_in A)"

syntax
  "_eventually_cosparse" :: "pttrn => 'a set => bool => bool"  ("(3__./ _)" [0, 0, 10] 10)
translations
  "xA. P" == "CONST eventually (λx. P) (CONST cosparse A)"

syntax
  "_qeventually_cosparse" :: "pttrn  bool  'a  'a"  ("(3_ | (_)./ _)" [0, 0, 10] 10)
translations
  "x|P. t" => "CONST eventually (λx. t) (CONST cosparse {x. P})"

print_translation let
  fun ev_cosparse_tr' [Abs (x, Tx, t), 
        Const (const_syntaxcosparse, _) $ (Const (const_syntaxCollect, _) $ Abs (y, Ty, P))] =
        if x <> y then raise Match
        else
          let
            val x' = Syntax_Trans.mark_bound_body (x, Tx);
            val t' = subst_bound (x', t);
            val P' = subst_bound (x', P);
          in
            Syntax.const syntax_const‹_qeventually_cosparse› $
              Syntax_Trans.mark_bound_abs (x, Tx) $ P' $ t'
          end
    | ev_cosparse_tr' _ = raise Match;
in [(const_syntaxeventually, K ev_cosparse_tr')] end

lemma eventually_cosparse: "eventually P (cosparse A)  {x. ¬P x} sparse_in A"
  unfolding cosparse_def by (rule eventually_Abs_filter[OF is_filter_cosparse])

lemma eventually_not_in_cosparse:
  assumes "X sparse_in A"
  shows   "eventually (λx. x  X) (cosparse A)"
  using assms by (auto simp: eventually_cosparse)

lemma eventually_cosparse_open_eq:
  "open A  eventually P (cosparse A)  (xA. eventually P (at x))"
  unfolding eventually_cosparse
  by (subst sparse_in_open) (auto simp: islimpt_conv_frequently_at frequently_def)

lemma eventually_cosparse_imp_eventually_at:
  "eventually P (cosparse A)  x  A  eventually P (at x within B)"
  unfolding eventually_cosparse sparse_in_def
  apply (auto simp: islimpt_conv_frequently_at frequently_def)
   apply (metis UNIV_I eventually_at_topological)
  done

lemma eventually_in_cosparse:
  assumes "A  X" "open A"
  shows   "eventually (λx. x  X) (cosparse A)"
proof -
  have "eventually (λx. x  A) (cosparse A)"
    using assms by (auto simp: eventually_cosparse_open_eq intro: eventually_at_in_open')
  thus ?thesis
    by eventually_elim (use assms(1) in blast)
qed

lemma cosparse_eq_bot_iff: "cosparse A = bot  (xA. open {x})"
proof -
  have "cosparse A = bot  eventually (λ_. False) (cosparse A)"
    by (simp add: trivial_limit_def)
  also have "  (xA. open {x})"
    unfolding eventually_cosparse sparse_in_def
    by (auto simp: islimpt_UNIV_iff)
  finally show ?thesis .
qed

lemma cosparse_empty [simp]: "cosparse {} = bot"
  by (rule filter_eqI) (auto simp: eventually_cosparse sparse_in_def)

lemma cosparse_eq_bot_iff' [simp]: "cosparse (A :: 'a :: perfect_space set) = bot  A = {}"
  by (auto simp: cosparse_eq_bot_iff not_open_singleton)


end