Library mathcomp.analysis.topology

(* mathcomp analysis (c) 2017 Inria and AIST. License: CeCILL-C.              *)
From mathcomp Require Import all_ssreflect all_algebra finmap generic_quotient.
From mathcomp Require Import boolp classical_sets functions.
From mathcomp Require Import cardinality mathcomp_extra fsbigop.
Require Import reals signed.

Filters and basic topological notions This file develops tools for the manipulation of filters and basic topological notions. The development of topological notions builds on "filtered types". They are types equipped with an interface that associates to each element a set of sets, intended to represent a filter. The notions of limit and convergence are defined for filtered types and in the documentation below we call "canonical filter" of an element the set of sets associated to it by the interface of filtered types. monotonous A f := {in A &, {mono f : x y / x <= y}} \/ {in A &, {mono f : x y /~ x <= y}}.

Filters :

filteredType U == interface type for types whose elements represent sets of sets on U. These sets are intended to be filters on U but this is not enforced yet. FilteredType U T m == packs the function m: T -> set (set U) to build a filtered type of type filteredType U; T must have a pointedType structure. [filteredType U of T for cT] == T-clone of the filteredType U structure cT. [filteredType U of T] == clone of a canonical structure of filteredType U on T. Filtered.source Y Z == structure that records types X such that there is a function mapping functions of type X -> Y to filters on Z. Allows to infer the canonical filter associated to a function by looking at its source type. Filtered.Source F == if F : (X -> Y) -> set (set Z), packs X with F in a Filtered.source Y Z structure. nbhs p == set of sets associated to p (in a filtered type). filter_from D B == set of the supersets of the elements of the family of sets B whose indices are in the domain D. This is a filter if (B_i)_(i in D) forms a filter base. filter_prod F G == product of the filters F and G. [filter of x] == canonical filter associated to x. F `=>` G <-> G is included in F; F and G are sets of sets. F --> G <-> the canonical filter associated to G is included in the canonical filter associated to F. lim F == limit of the canonical filter associated with F if there is such a limit, i.e., an element l such that the canonical filter associated to l is a subset of F. [lim F in T] == limit of the canonical filter associated to F in T where T has type filteredType U. [cvg F in T] <-> the canonical filter associated to F converges in T. cvg F <-> same as [cvg F in T] where T is inferred from the type of the canonical filter associated to F. Filter F == type class proving that the set of sets F is a filter. ProperFilter F == type class proving that the set of sets F is a proper filter. UltraFilter F == type class proving that the set of sets F is an ultrafilter filter_on T == interface type for sets of sets on T that are filters. FilterType F FF == packs the set of sets F with the proof FF of Filter F to build a filter_on T structure. pfilter_on T == interface type for sets of sets on T that are proper filters. PFilterPack F FF == packs the set of sets F with the proof FF of ProperFilter F to build a pfilter_on T structure. fmap f F == image of the filter F by the function f E @ [x --> F] == image of the canonical filter associated to F by the function (fun x => E). f @ F == image of the canonical filter associated to F by the function f. fmapi f F == image of the filter F by the relation f E `@ [x --> F] == image of the canonical filter associated to F by the relation (fun x => E). f `@ F == image of the canonical filter associated to F by the relation f. globally A == filter of the sets containing A. @frechet_filter T := [set S : set T | finite_set (~` S) ] a.k.a. cofinite filter at_point a == filter of the sets containing a. within D F == restriction of the filter F to the domain D. principal_filter x == filter containing every superset of x. subset_filter F D == similar to within D F, but with dependent types. powerset_filter_from F == The filter of downward closed subsets of F. Enables use of near notation to pick suitably small members of F in_filter F == interface type for the sets that belong to the set of sets F. InFilter FP == packs a set P with a proof of F P to build a in_filter F structure. \oo == "eventually" filter on nat: set of predicates on natural numbers that are eventually true. clopen U == U is both open and closed normal_space X == X is normal, sometimes called T4 regular_space X == X is regular, sometimes called T3 separate_points_from_closed f == For a closed set U and point x outside some member of the family f sends f_i(x) outside (closure (f_i @` U)). Used together with join_product. join_product f == The function (x => f ^~ x). When the family f separates points from closed sets, join_product is an embedding.

Near notations and tactics:

--> The purpose of the near notations and tactics is to make the manipulation of filters easier. Instead of proving F G, one can prove G x for x "near F", i.e. for x such that H x for H arbitrarily precise as long as F H. The near tactics allow for a delayed introduction of H: H is introduced as an existential variable and progressively instantiated during the proof process. --> Notations: {near F, P} == the property P holds near the canonical filter associated to F; P must have the form forall x, Q x. Equivalent to F Q. \forall x \near F, P x <-> F (fun x => P x). \near x, P x := \forall y \near x, P y. {near F & G, P} == same as {near H, P}, where H is the product of the filters F and G. \forall x \near F & y \near G, P x y := {near F & G, forall x y, P x y}. \forall x & y \near F, P x y == same as before, with G = F. \near x & y, P x y := \forall z \near x & t \near y, P x y. x \is_near F == x belongs to a set P : in_filter F. --> Tactics:
  • near=> x introduces x: On the goal \forall x \near F, G x, introduces the variable x and an "existential", and unaccessible hypothesis ?H x and asks the user to prove (G x) in this context. Under the hood delays the proof of F ?H and waits for near: x Also exists under the form near=> x y.
  • near: x discharges x: On the goal H_i x, and where x \is_near F, it asks the user to prove that (\forall x \near F, H_i x), provided that H_i x does not depend on variables introduced after x. Under the hood, it refines by intersection the existential variable ?H attached to x, computes the intersection with F, and asks the user to prove F H_i, right now
  • end_near should be used to close remaining existentials trivially
  • near F => x poses a variable near F, where F is a proper filter adds to the context a variable x that \is_near F, i.e. one may assume H x for any H in F. This new variable x can be dealt with using near: x, as for variables introduced by near=>.

Topology :

topologicalType == interface type for topological space structure. TopologicalMixin nbhs_filt nbhsE == builds the mixin for a topological space from the proofs that nbhs outputs proper filters and defines the same notion of neighbourhood as the open sets. topologyOfFilterMixin nbhs_filt nbhs_sing nbhs_nbhs == builds the mixin for a topological space from the properties of nbhs and hence assumes that the carrier is a filterType topologyOfOpenMixin opT opI op_bigU == builds the mixin for a topological space from the properties of open sets, assuming the carrier is a pointed type. nbhs_of_open must be used to declare a filterType. topologyOfBaseMixin b_cover b_join == builds the mixin for a topological space from the properties of a base of open sets; the type of indices must be a pointedType, as well as the carrier. nbhs_of_open \o open_from must be used to declare a filterType filterI_iter F n == nth stage of recursively building the filter of finite intersections of F finI_from D f == set of \bigcap_(i in E) f i where E is a finite subset of D topologyOfSubbaseMixin D b == builds the mixin for a topological space from a subbase of open sets b indexed on domain D; the type of indices must be a pointedType. TopologicalType T m == packs the mixin m to build a topologicalType; T must have a canonical structure of filteredType T. weak_topologicalType f == weak topology by f : S -> T on S; S must be a pointedType and T a topologicalType. sup_topologicalType Tc == supremum topology of the family of topologicalType structures Tc on T; T must be a pointedType. product_topologicalType T == product topology of the family of topologicalTypes T. [topologicalType of T for cT] == T-clone of the topologicalType structure cT. [topologicalType of T] == clone of a canonical structure of topologicalType on T. open == set of open sets. open_nbhs p == set of open neighbourhoods of p. basis B == a family of open sets that converges to each point second_countable T == T has a countable basis continuous f <-> f is continuous w.r.t the topology. x^' == set of neighbourhoods of x where x is excluded (a "deleted neighborhood"). closure A == closure of the set A. limit_point E == the set of limit points of E closed == set of closed sets. cluster F == set of cluster points of F. compact == set of compact sets w.r.t. the filter- based definition of compactness. compact_near F == the filter F contains a closed comapct set precompact A == The set A is contained in a closed and compact set locally_compact A == every point in A has a compact (and closed) neighborhood hausdorff_space T <-> T is a Hausdorff space (T_2). discrete_space T <-> every nbhs is a principal filter finite_subset_cover D F A == the family of sets F is a cover of A for a finite number of indices in D cover_compact == set of compact sets w.r.t. the open cover-based definition of compactness. near_covering == a reformulation of covering compact better suited for use with `near` connected A <-> the only non empty subset of A which is both open and closed in A is A. kolmogorov_space T <-> T is a Kolmogorov space (T_0). accessible_space T <-> T is an accessible space (T_1). separated A B == the two sets A and B are separated component x == the connected component of point x perfect_set A == A is closed, and is every point in A is a limit point of A. totally_disconnected A == The only connected subsets of A are empty or singletons. zero_dimensional T == Points are separable by a clopen set. set_nbhs A == filter from open sets containing A [locally P] := forall a, A a -> G (within A (nbhs x)) if P is convertible to G (globally A) quotient_topology Q == the quotient topology corresponding to quotient Q : quotType T where T has type topologicalType

Function space topologies :

{uniform` A -> V} == The space U -> V, equipped with the topology of uniform convergence from a set A to V, where V is a uniformType. {uniform U -> V} := {uniform` [set: U] -> V} {uniform A, F --> f} == F converges to f in {uniform A -> V}. {uniform, F --> f} := {uniform setT, F --> f} {ptws U -> V} == The space U -> V, equipped with the topology of pointwise convergence from U to V, where V is a topologicalType; notation for @fct_Pointwise U V. {ptws, F --> f} == F converges to f in {ptws U -> V}. {family fam, U -> V} == The space U -> V, equipped with the supremum topology of {uniform A -> f} for each A in 'fam' In particular {family compact, U -> V} is the topology of compact convergence. {family fam, F --> f} == F converges to f in {family fam, U -> V}. --> We used these topological notions to prove Tychonoff's Theorem, which states that any product of compact sets is compact according to the product topology.

Uniform spaces :

nbhs_ ent == neighbourhoods defined using entourages uniformType == interface type for uniform spaces: a type equipped with entourages UniformMixin efilter erefl einv esplit nbhse == builds the mixin for a uniform space from the properties of entourages and the compatibility between entourages and nbhs UniformType T m == packs the uniform space mixin into a uniformType. T must have a canonical structure of topologicalType [uniformType of T for cT] == T-clone of the uniformType structure cT [uniformType of T] == clone of a canonical structure of uniformType on T topologyOfEntourageMixin umixin == builds the mixin for a topological space from a mixin for a uniform space entourage == set of entourages in a uniform space split_ent E == when E is an entourage, split_ent E is an entourage E' such that E' \o E' is included in E when seen as a relation unif_continuous f <-> f is uniformly continuous. weak_uniformType == the uniform space for weak topologies sup_uniformType == the uniform space for sup topologies countable_uniformity T == T's entourage has a countable base. This is equivalent to `T` being metrizable gauge E == For an entourage E, gauge E is a filter which includes `iter n split_ent E`. Critically, `gauge E` forms a uniform space with a countable uniformity gauge_psuedoMetricType E == the pseudoMetricType associated with the `gauge E` discrete_ent == entourages for the discrete topology

PseudoMetric spaces :

entourage_ ball == entourages defined using balls pseudoMetricType == interface type for pseudo metric space structure: a type equipped with balls. PseudoMetricMixin brefl bsym btriangle nbhsb == builds the mixin for a pseudo metric space from the properties of balls and the compatibility between balls and entourages. PseudoMetricType T m == packs the pseudo metric space mixin into a pseudoMetricType. T must have a canonical structure of uniformType. [pseudoMetricType R of T for cT] == T-clone of the pseudoMetricType structure cT, with R the ball radius. [pseudoMetricType R of T] == clone of a canonical structure of pseudoMetricType on T, with R the ball radius. uniformityOfBallMixin umixin == builds the mixin for a topological space from a mixin for a pseudoMetric space. ball x e == ball of center x and radius e. nbhs_ball_ ball == nbhs defined using the given balls nbhs_ball == nbhs defined using balls in a pseudometric space close x y <-> x and y are arbitrarily close w.r.t. to balls. weak_pseudoMetricType == the metric space for weak topologies quotient_topology Q == the quotient topology corresponding to quotient Q : quotType T. where T has type topologicalType discrete_ball == singleton balls for thediscrete topology

Complete uniform spaces :

cauchy F <-> the set of sets F is a cauchy filter (entourage definition) completeType == interface type for a complete uniform space structure. CompleteType T cvgCauchy == packs the proof that every proper cauchy filter on T converges into a completeType structure; T must have a canonical structure of uniformType. [completeType of T for cT] == T-clone of the completeType structure cT. [completeType of T] == clone of a canonical structure of completeType on T.

Complete pseudometric spaces :

cauchy_ex F <-> the set of sets F is a cauchy filter (epsilon-delta definition). cauchy F <-> the set of sets F is a cauchy filter (using the near notations). completePseudoMetricType == interface type for a complete pseudometric space structure. CompletePseudoMetricType T cvgCauchy == packs the proof that every proper cauchy filter on T converges into a completePseudoMetricType structure; T must have a canonical structure of pseudoMetricType. [completePseudoMetricType of T for cT] == T-clone of the completePseudoMetricType structure cT. [completePseudoMetricType of T] == clone of a canonical structure of completePseudoMetricType on T. ball_ N == balls defined by the norm/absolute value N dense S == the set (S : set T) is dense in T, with T of type topologicalType

Subspaces of topological spaces :

subspace A == for (A : set T), this is a copy of T with a topology that ignores points outside A incl_subspace x == with x of type subspace A with (A : set T), inclusion of subspace A into T

Arzela Ascoli' theorem :

singletons T := [set [set x] | x in [set: T] ]. equicontinuous W x == the set (W : X -> Y) is equicontinuous at x pointwise_precompact W == For each (x : X), set of images [f x | f in W] is precompact We endow several standard types with the types of topological notions:
  • products: prod_topologicalType, prod_uniformType, prod_pseudoMetricType sup_pseudoMetricType, weak_pseudoMetricType, product_pseudoMetricType
  • matrices: matrix_filtered, matrix_topologicalType, matrix_uniformType, matrix_pseudoMetricType, matrix_completeType, matrix_completePseudoMetricType
  • nat: nat_filteredType, nat_topologicalType
  • numFieldType: numField_filteredType, numField_topologicalType, numField_uniformType, numField_pseudoMetricType (accessible with "Import numFieldTopology.Exports.")

Reserved Notation "{ 'near' x , P }" (at level 0, format "{ 'near' x , P }").
Reserved Notation "'\forall' x '\near' x_0 , P"
  (at level 200, x name, P at level 200,
   format "'\forall' x '\near' x_0 , P").
Reserved Notation "'\near' x , P"
  (at level 200, x at level 99, P at level 200,
   format "'\near' x , P", only parsing).
Reserved Notation "{ 'near' x & y , P }"
  (at level 0, format "{ 'near' x & y , P }").
Reserved Notation "'\forall' x '\near' x_0 & y '\near' y_0 , P"
  (at level 200, x name, y name, P at level 200,
   format "'\forall' x '\near' x_0 & y '\near' y_0 , P").
Reserved Notation "'\forall' x & y '\near' z , P"
  (at level 200, x name, y name, P at level 200,
   format "'\forall' x & y '\near' z , P").
Reserved Notation "'\near' x & y , P"
  (at level 200, x, y at level 99, P at level 200,
   format "'\near' x & y , P", only parsing).
Reserved Notation "[ 'filter' 'of' x ]" (format "[ 'filter' 'of' x ]").
Reserved Notation "F `=>` G" (at level 70, format "F `=>` G").
Reserved Notation "F --> G" (at level 70, format "F --> G").
Reserved Notation "[ 'lim' F 'in' T ]" (format "[ 'lim' F 'in' T ]").
Reserved Notation "[ 'cvg' F 'in' T ]" (format "[ 'cvg' F 'in' T ]").
Reserved Notation "x \is_near F" (at level 10, format "x \is_near F").
Reserved Notation "E @[ x --> F ]"
  (at level 60, x name, format "E @[ x --> F ]").
Reserved Notation "f @ F" (at level 60, format "f @ F").
Reserved Notation "E `@[ x --> F ]"
  (at level 60, x name, format "E `@[ x --> F ]").
Reserved Notation "f `@ F" (at level 60, format "f `@ F").
Reserved Notation "A ^°" (at level 1, format "A ^°").
Reserved Notation "[ 'locally' P ]" (at level 0, format "[ 'locally' P ]").
Reserved Notation "x ^'" (at level 2, format "x ^'").
Reserved Notation "{ 'within' A , 'continuous' f }"
  (at level 70, A at level 69, format "{ 'within' A , 'continuous' f }").
Reserved Notation "{ 'uniform`' A -> V }"
  (at level 0, A at level 69, format "{ 'uniform`' A -> V }").
Reserved Notation "{ 'uniform' U -> V }"
  (at level 0, U at level 69, format "{ 'uniform' U -> V }").
Reserved Notation "{ 'uniform' A , F --> f }"
  (at level 0, A at level 69, F at level 69,
   format "{ 'uniform' A , F --> f }").
Reserved Notation "{ 'uniform' , F --> f }"
  (at level 0, F at level 69,
   format "{ 'uniform' , F --> f }").
Reserved Notation "{ 'ptws' U -> V }"
  (at level 0, U at level 69, format "{ 'ptws' U -> V }").
Reserved Notation "{ 'ptws' , F --> f }"
  (at level 0, F at level 69, format "{ 'ptws' , F --> f }").
Reserved Notation "{ 'family' fam , U -> V }"
  (at level 0, U at level 69, format "{ 'family' fam , U -> V }").
Reserved Notation "{ 'family' fam , F --> f }"
  (at level 0, F at level 69, format "{ 'family' fam , F --> f }").

Set Implicit Arguments.

Making sure that [Program] does not automatically introduce
Obligation Tactic := idtac.

Import Order.TTheory GRing.Theory Num.Theory.
Local Open Scope classical_set_scope.
Local Open Scope ring_scope.

Section bigmaxmin.
Local Open Scope order_scope.
Variables (d : unit) (T : orderType d) (x : T) (I : finType) (P : pred I)
          (m : T) (F : I T).

Lemma bigmax_geP : reflect (m x exists2 i, P i & m F i)
                           (m \big[max/x]_(i | P i) F i).

Lemma bigmax_gtP : reflect (m < x exists2 i, P i & m < F i)
                           (m < \big[max/x]_(i | P i) F i).

Lemma bigmin_leP : reflect (x m exists2 i, P i & F i m)
                           (\big[min/x]_(i | P i) F i m).

Lemma bigmin_ltP : reflect (x < m exists2 i, P i & F i < m)
                           (\big[min/x]_(i | P i) F i < m).

End bigmaxmin.

Definition monotonous d (T : porderType d) (pT : predType T) (A : pT) (f : T T) :=
  {in A &, {mono f : x y / (x y)%O}} {in A &, {mono f : x y /~ (x y)%O}}.

Lemma and_prop_in (T : Type) (p : mem_pred T) (P Q : T Prop) :
  {in p, x, P x Q x}
  {in p, x, P x} {in p, x, Q x}.

Lemma mem_inc_segment d (T : porderType d) (a b : T) (f : T T) :
    {in `[a, b] &, {mono f : x y / (x y)%O}}
  {homo f : x / x \in `[a, b] >-> x \in `[f a, f b]}.

Lemma mem_dec_segment d (T : porderType d) (a b : T) (f : T T) :
    {in `[a, b] &, {mono f : x y /~ (x y)%O}}
  {homo f : x / x \in `[a, b] >-> x \in `[f b, f a]}.

Section Linear1.
Context (R : ringType) (U : lmodType R) (V : zmodType) (s : R V V).
Canonical linear_eqType := EqType {linear U V | s} gen_eqMixin.
Canonical linear_choiceType := ChoiceType {linear U V | s} gen_choiceMixin.
End Linear1.
Section Linear2.
Context (R : ringType) (U : lmodType R) (V : zmodType) (s : R V V)
        (s_law : GRing.Scale.law s).
Canonical linear_pointedType := PointedType {linear U V | GRing.Scale.op s_law}
                                            (@GRing.null_fun_linear R U V s s_law).
End Linear2.

Module Filtered.

Index a family of filters on a type, one for each element of the type
Definition nbhs_of U T := T set (set U).
Record class_of U T := Class {
  base : Pointed.class_of T;
  nbhs_op : nbhs_of U T
}.

Section ClassDef.
Variable U : Type.

Structure type := Pack { sort; _ : class_of U sort }.
Variables (T : Type) (cT : type).
Definition class := let: Pack _ c := cT return class_of U cT in c.

Definition clone c of phant_id class c := @Pack T c.
Let xT := let: Pack T _ := cT in T.
Notation xclass := (class : class_of U xT).

Definition pack m :=
  fun bT b of phant_id (Pointed.class bT) b ⇒ @Pack T (Class b m).

Definition eqType := @Equality.Pack cT xclass.
Definition choiceType := @Choice.Pack cT xclass.
Definition fpointedType := @Pointed.Pack cT xclass.

End ClassDef.

filter on arrow sources
Structure source Z Y := Source {
  source_type :> Type;
  _ : (source_type Z) set (set Y)
}.
Definition source_filter Z Y (F : source Z Y) : (F Z) set (set Y) :=
  let: Source X f := F in f.

Module Exports.
Coercion sort : type >-> Sortclass.
Coercion base : class_of >-> Pointed.class_of.
Coercion nbhs_op : class_of >-> nbhs_of.
Coercion eqType : type >-> Equality.type.
Canonical eqType.
Coercion choiceType : type >-> Choice.type.
Canonical choiceType.
Coercion fpointedType : type >-> Pointed.type.
Canonical fpointedType.
Notation filteredType := type.
Notation FilteredType U T m := (@pack U T m _ _ idfun).
Notation "[ 'filteredType' U 'of' T 'for' cT ]" := (@clone U T cT _ idfun)
  (at level 0, format "[ 'filteredType' U 'of' T 'for' cT ]") : form_scope.
Notation "[ 'filteredType' U 'of' T ]" := (@clone U T _ _ id)
  (at level 0, format "[ 'filteredType' U 'of' T ]") : form_scope.

The default filter for an arbitrary element is the one obtained from its type
Canonical default_arrow_filter Y (Z : pointedType) (X : source Z Y) :=
  FilteredType Y (X Z) (@source_filter _ _ X).
Canonical source_filter_filter Y :=
  @Source Prop _ (_ Prop) (fun x : (set (set Y)) ⇒ x).
Canonical source_filter_filter' Y :=
  @Source Prop _ (set _) (fun x : (set (set Y)) ⇒ x).

End Exports.
End Filtered.
Export Filtered.Exports.

Definition nbhs {U} {T : filteredType U} : T set (set U) :=
  Filtered.nbhs_op (Filtered.class T).
Arguments nbhs {U T} _ _ : simpl never.

Definition filter_from {I T : Type} (D : set I) (B : I set T) : set (set T) :=
  [set P | exists2 i, D i & B i `<=` P].

the canonical filter on matrices on X is the product of the canonical filter on X
Canonical matrix_filtered m n X (Z : filteredType X) : filteredType 'M[X]_(m, n) :=
  FilteredType 'M[X]_(m, n) 'M[Z]_(m, n) (fun mxfilter_from
    [set P | i j, nbhs (mx i j) (P i j)]
    (fun P[set my : 'M[X]_(m, n) | i j, P i j (my i j)])).

Definition filter_prod {T U : Type}
  (F : set (set T)) (G : set (set U)) : set (set (T × U)) :=
  filter_from (fun PF P.1 G P.2) (fun PP.1 `*` P.2).

Section Near.


Definition prop_near1 {X} {fX : filteredType X} (x : fX)
   P (phP : ph {all1 P}) := nbhs x P.

Definition prop_near2 {X X'} {fX : filteredType X} {fX' : filteredType X'}
  (x : fX) (x' : fX') := fun P of ph {all2 P}
  filter_prod (nbhs x) (nbhs x') (fun xP x.1 x.2).

End Near.

Notation "{ 'near' x , P }" := (@prop_near1 _ _ x _ (inPhantom P)) : type_scope.
Notation "'\forall' x '\near' x_0 , P" := {near x_0, x, P} : type_scope.
Notation "'\near' x , P" := (\ x \near x, P) : type_scope.
Notation "{ 'near' x & y , P }" :=
  (@prop_near2 _ _ _ _ x y _ (inPhantom P)) : type_scope.
Notation "'\forall' x '\near' x_0 & y '\near' y_0 , P" :=
  {near x_0 & y_0, x y, P} : type_scope.
Notation "'\forall' x & y '\near' z , P" :=
  {near z & z, x y, P} : type_scope.
Notation "'\near' x & y , P" := (\ x \near x & y \near y, P) : type_scope.
Arguments prop_near1 : simpl never.
Arguments prop_near2 : simpl never.

Lemma nearE {T} {F : set (set T)} (P : set T) : (\ x \near F, P x) = F P.

Lemma eq_near {T} {F : set (set T)} (P Q : set T) :
   ( x, P x Q x)
   (\ x \near F, P x) = (\ x \near F, Q x).

Definition filter_of X (fX : filteredType X) (x : fX) of phantom fX x :=
   nbhs x.
Notation "[ 'filter' 'of' x ]" :=
  (@filter_of _ _ _ (Phantom _ x)) : classical_set_scope.
Arguments filter_of _ _ _ _ _ /.

Lemma filter_of_filterE {T : Type} (F : set (set T)) : [filter of F] = F.

Lemma nbhs_filterE {T : Type} (F : set (set T)) : nbhs F = F.

Module Export NbhsFilter.
Definition nbhs_simpl := (@filter_of_filterE, @nbhs_filterE).
End NbhsFilter.

Definition cvg_to {T : Type} (F G : set (set T)) := G `<=` F.
Notation "F `=>` G" := (cvg_to F G) : classical_set_scope.
Lemma cvg_refl T (F : set (set T)) : F `=>` F.
Arguments cvg_refl {T F}.
#[global] Hint Resolve cvg_refl : core.

Lemma cvg_trans T (G F H : set (set T)) :
  (F `=>` G) (G `=>` H) (F `=>` H).

Notation "F --> G" := (cvg_to [filter of F] [filter of G]) : classical_set_scope.
Definition type_of_filter {T} (F : set (set T)) := T.

Definition lim_in {U : Type} (T : filteredType U) :=
  fun F : set (set U) ⇒ get (fun l : TF --> l).
Notation "[ 'lim' F 'in' T ]" := (@lim_in _ T [filter of F]) : classical_set_scope.
Notation lim F := [lim F in [filteredType _ of @type_of_filter _ [filter of F]]].
Notation "[ 'cvg' F 'in' T ]" := (F --> [lim F in T]) : classical_set_scope.
Notation cvg F := [cvg F in [filteredType _ of @type_of_filter _ [filter of F]]].

Section FilteredTheory.

Canonical filtered_prod X1 X2 (Z1 : filteredType X1)
  (Z2 : filteredType X2) : filteredType (X1 × X2) :=
  FilteredType (X1 × X2) (Z1 × Z2)
    (fun xfilter_prod (nbhs x.1) (nbhs x.2)).

Lemma cvg_prod T {U U' V V' : filteredType T} (x : U) (l : U') (y : V) (k : V') :
  x --> l y --> k (x, y) --> (l, k).

Lemma cvg_ex {U : Type} (T : filteredType U) (F : set (set U)) :
  [cvg F in T] ( l : T, F --> l).

Lemma cvgP {U : Type} (T : filteredType U) (F : set (set U)) (l : T) :
   F --> l [cvg F in T].

Lemma cvg_toP {U : Type} (T : filteredType U) (F : set (set U)) (l : T) :
   [cvg F in T] [lim F in T] = l F --> l.

Lemma dvgP {U : Type} (T : filteredType U) (F : set (set U)) :
  ¬ [cvg F in T] [lim F in T] = point.

Lemma cvgNpoint {U} (T : filteredType U) (F : set (set U)) :
  [lim F in T] != point [cvg F in T].

End FilteredTheory.
Arguments cvgP {U T F} l.
Arguments dvgP {U} T {F}.

Lemma nbhs_nearE {U} {T : filteredType U} (x : T) (P : set U) :
  nbhs x P = \near x, P x.

Lemma near_nbhs {U} {T : filteredType U} (x : T) (P : set U) :
  (\ x \near nbhs x, P x) = \near x, P x.

Lemma near2_curry {U V} (F : set (set U)) (G : set (set V)) (P : U set V) :
  {near F & G, x y, P x y} = {near (F, G), x, P x.1 x.2}.

Lemma near2_pair {U V} (F : set (set U)) (G : set (set V)) (P : set (U × V)) :
  {near F & G, x y, P (x, y)} = {near (F, G), x, P x}.

Definition near2E := (@near2_curry, @near2_pair).

Lemma filter_of_nearI (X : Type) (fX : filteredType X)
  (x : fX) (ph : phantom fX x) : P,
  @filter_of X fX x ph P = @prop_near1 X fX x P (inPhantom ( x, P x)).

Module Export NearNbhs.
Definition near_simpl := (@near_nbhs, @nbhs_nearE, filter_of_nearI).
Ltac near_simpl := rewrite ?near_simpl.
End NearNbhs.

Lemma near_swap {U V} (F : set (set U)) (G : set (set V)) (P : U set V) :
  (\ x \near F & y \near G, P x y) = (\ y \near G & x \near F, P x y).

Filters

Definitions


Class Filter {T : Type} (F : set (set T)) := {
  filterT : F setT ;
  filterI : P Q : set T, F P F Q F (P `&` Q) ;
  filterS : P Q : set T, P `<=` Q F P F Q
}.

Class ProperFilter' {T : Type} (F : set (set T)) := {
  filter_not_empty : not (F (fun _False)) ;
  filter_filter' : Filter F
}.
TODO: Reuse :> above and remove the following line and the coercion below after 8.17 is the minimum required version for Coq
Arguments filter_not_empty {T} F {_}.

Notation ProperFilter := ProperFilter'.

Lemma filter_setT (T' : Type) : Filter [set: set T'].

Lemma filterP_strong T (F : set (set T)) {FF : Filter F} (P : set T) :
  ( Q : set T, FQ : F Q, x : T, Q x P x) F P.

Structure filter_on T := FilterType {
  filter :> (T Prop) Prop;
  _ : Filter filter
}.
Definition filter_class T (F : filter_on T) : Filter F :=
  let: FilterType _ class := F in class.
Arguments FilterType {T} _ _.
#[global] Existing Instance filter_class.
Typeclasses Opaque filter.
Coercion filter_filter' : ProperFilter >-> Filter.

Structure pfilter_on T := PFilterPack {
  pfilter :> (T Prop) Prop;
  _ : ProperFilter pfilter
}.
Definition pfilter_class T (F : pfilter_on T) : ProperFilter F :=
  let: PFilterPack _ class := F in class.
Arguments PFilterPack {T} _ _.
#[global] Existing Instance pfilter_class.
Typeclasses Opaque pfilter.
Canonical pfilter_filter_on T (F : pfilter_on T) :=
  FilterType F (pfilter_class F).
Coercion pfilter_filter_on : pfilter_on >-> filter_on.
Definition PFilterType {T} (F : (T Prop) Prop)
  {fF : Filter F} (fN0 : not (F set0)) :=
  PFilterPack F (Build_ProperFilter' fN0 fF).
Arguments PFilterType {T} F {fF} fN0.

Canonical filter_on_eqType T := EqType (filter_on T) gen_eqMixin.
Canonical filter_on_choiceType T :=
  ChoiceType (filter_on T) gen_choiceMixin.
Canonical filter_on_PointedType T :=
  PointedType (filter_on T) (FilterType _ (filter_setT T)).
Canonical filter_on_FilteredType T :=
  FilteredType T (filter_on T) (@filter T).

Global Instance filter_on_Filter T (F : filter_on T) : Filter F.
Global Instance pfilter_on_ProperFilter T (F : pfilter_on T) : ProperFilter F.

Lemma nbhs_filter_onE T (F : filter_on T) : nbhs F = nbhs (filter F).
Definition nbhs_simpl := (@nbhs_simpl, @nbhs_filter_onE).

Lemma near_filter_onE T (F : filter_on T) (P : set T) :
  (\ x \near F, P x) = \ x \near filter F, P x.
Definition near_simpl := (@near_simpl, @near_filter_onE).

Program Definition trivial_filter_on T := FilterType [set setT : set T] _.
Canonical trivial_filter_on.

Lemma filter_nbhsT {T : Type} (F : set (set T)) :
   Filter F nbhs F setT.
#[global] Hint Resolve filter_nbhsT : core.

Lemma nearT {T : Type} (F : set (set T)) : Filter F \near F, True.
#[global] Hint Resolve nearT : core.

Lemma filter_not_empty_ex {T : Type} (F : set (set T)) :
    ( P, F P x, P x) ¬ F set0.

Definition Build_ProperFilter {T : Type} (F : set (set T))
  (filter_ex : P, F P x, P x)
  (filter_filter : Filter F) :=
  Build_ProperFilter' (filter_not_empty_ex filter_ex) (filter_filter).

Lemma filter_ex_subproof {T : Type} (F : set (set T)) :
     ¬ F set0 ( P, F P x, P x).

Definition filter_ex {T : Type} (F : set (set T)) {FF : ProperFilter F} :=
  filter_ex_subproof (filter_not_empty F).
Arguments filter_ex {T F FF _}.

Lemma filter_getP {T : pointedType} (F : set (set T)) {FF : ProperFilter F}
      (P : set T) : F P P (get P).

Near Tactic

Record in_filter T (F : set (set T)) := InFilter {
  prop_in_filter_proj : T Prop;
  prop_in_filterP_proj : F prop_in_filter_proj
}.
add ball x e as a canonical instance of nbhs x

Module Type PropInFilterSig.
Axiom t : (T : Type) (F : set (set T)), in_filter F T Prop.
Axiom tE : t = prop_in_filter_proj.
End PropInFilterSig.
Module PropInFilter : PropInFilterSig.
Definition t := prop_in_filter_proj.
Lemma tE : t = prop_in_filter_proj.
End PropInFilter.
Coercion PropInFilter.t : in_filter >-> Funclass.
Notation prop_of := PropInFilter.t.
Definition prop_ofE := PropInFilter.tE.
Notation "x \is_near F" := (@PropInFilter.t _ F _ x).
Definition is_nearE := prop_ofE.

Lemma prop_ofP T F (iF : @in_filter T F) : F (prop_of iF).

Definition in_filterT T F (FF : Filter F) : @in_filter T F :=
  InFilter (filterT).
Canonical in_filterI T F (FF : Filter F) (P Q : @in_filter T F) :=
  InFilter (filterI (prop_in_filterP_proj P) (prop_in_filterP_proj Q)).

Lemma filter_near_of T F (P : @in_filter T F) (Q : set T) : Filter F
  ( x, prop_of P x Q x) F Q.

Fact near_key : unit.

Lemma mark_near (P : Prop) : locked_with near_key P P.

Lemma near_acc T F (P : @in_filter T F) (Q : set T) (FF : Filter F)
   (FQ : \ x \near F, Q x) :
   locked_with near_key ( x, prop_of (in_filterI FF P (InFilter FQ)) x Q x).

Lemma near_skip_subproof T F (P Q : @in_filter T F) (G : set T) (FF : Filter F) :
   locked_with near_key ( x, prop_of P x G x)
   locked_with near_key ( x, prop_of (in_filterI FF P Q) x G x).

Tactic Notation "near=>" ident(x) := apply: filter_near_ofx ?.

Ltac just_discharge_near x :=
  tryif match goal with Hx : x \is_near _ |- _move: (x) (Hx); apply: mark_near end
        then idtac else fail "the variable" x "is not a ""near"" variable".
Ltac near_skip :=
  match goal with |- locked_with near_key ( _, @PropInFilter.t _ _ ?P _ _) ⇒
    tryif is_evar P then fail "nothing to skip" else apply: near_skip_subproof end.

Tactic Notation "near:" ident(x) :=
  just_discharge_near x;
  tryif do ![apply: near_acc; first shelve|near_skip]
  then idtac
  else fail "the goal depends on variables introduced after" x.

Ltac under_near i tac := neari; tac; near: i.
Tactic Notation "near=>" ident(i) "do" tactic1(tac) := under_near i ltac:(tac).
Tactic Notation "near=>" ident(i) "do" "[" tactic4(tac) "]" := neari do tac.
Tactic Notation "near" "do" tactic1(tac) :=
  let i := fresh "i" in under_near i ltac:(tac).
Tactic Notation "near" "do" "[" tactic4(tac) "]" := near do tac.

Ltac end_near := do ?exact: in_filterT.

Ltac done :=
  trivial; hnf; intros; solve
   [ do ![solve [trivial | apply: sym_equal; trivial]
         | discriminate | contradiction | split]
   | case not_locked_false_eq_true; assumption
   | match goal with H : ¬ _ |- _solve [case H; trivial] end
   | match goal with |- ?x \is_near _near: x; apply: prop_ofP end ].

Lemma have_near (U : Type) (fT : filteredType U) (x : fT) (P : Prop) :
  ProperFilter (nbhs x) (\ x \near x, P) P.
Arguments have_near {U fT} x.

Tactic Notation "near" constr(F) "=>" ident(x) :=
  apply: (have_near F); nearx.

Lemma near T (F : set (set T)) P (FP : F P) (x : T)
  (Px : prop_of (InFilter FP) x) : P x.
Arguments near {T F P} FP x Px.

Lemma nearW {T : Type} {F : set (set T)} (P : T Prop) :
  Filter F ( x, P x) (\ x \near F, P x).

Lemma filterE {T : Type} {F : set (set T)} :
  Filter F P : set T, ( x, P x) F P.

Lemma filter_app (T : Type) (F : set (set T)) :
  Filter F P Q : set T, F (fun xP x Q x) F P F Q.

Lemma filter_app2 (T : Type) (F : set (set T)) :
  Filter F P Q R : set T, F (fun xP x Q x R x)
  F P F Q F R.

Lemma filter_app3 (T : Type) (F : set (set T)) :
  Filter F P Q R S : set T, F (fun xP x Q x R x S x)
  F P F Q F R F S.

Lemma filterS2 (T : Type) (F : set (set T)) :
  Filter F P Q R : set T, ( x, P x Q x R x)
  F P F Q F R.

Lemma filterS3 (T : Type) (F : set (set T)) :
  Filter F P Q R S : set T, ( x, P x Q x R x S x)
  F P F Q F R F S.

Lemma filter_const {T : Type} {F} {FF: @ProperFilter T F} (P : Prop) :
  F (fun P) P.

Lemma in_filter_from {I T : Type} (D : set I) (B : I set T) (i : I) :
  D i filter_from D B (B i).

Lemma near_andP {T : Type} F (b1 b2 : T Prop) : Filter F
  (\ x \near F, b1 x b2 x)
    (\ x \near F, b1 x) (\ x \near F, b2 x).

Lemma nearP_dep {T U} {F : set (set T)} {G : set (set U)}
   {FF : Filter F} {FG : Filter G} (P : T U Prop) :
  (\ x \near F & y \near G, P x y)
  \ x \near F, \ y \near G, P x y.

Lemma filter2P T U (F : set (set T)) (G : set (set U))
  {FF : Filter F} {FG : Filter G} (P : set (T × U)) :
  (exists2 Q : set T × set U, F Q.1 G Q.2
     & (x : T) (y : U), Q.1 x Q.2 y P (x, y))
    \ x \near (F, G), P x.

Lemma filter_ex2 {T U : Type} (F : set (set T)) (G : set (set U))
  {FF : ProperFilter F} {FG : ProperFilter G} (P : set T) (Q : set U) :
    F P G Q x : T, exists2 y : U, P x & Q y.
Arguments filter_ex2 {T U F G FF FG _ _}.

Lemma filter_fromP {I T : Type} (D : set I) (B : I set T) (F : set (set T)) :
  Filter F F `=>` filter_from D B i, D i F (B i).

Lemma filter_fromTP {I T : Type} (B : I set T) (F : set (set T)) :
  Filter F F `=>` filter_from setT B i, F (B i).

Lemma filter_from_filter {I T : Type} (D : set I) (B : I set T) :
  ( i : I, D i)
  ( i j, D i D j exists2 k, D k & B k `<=` B i `&` B j)
  Filter (filter_from D B).

Lemma filter_fromT_filter {I T : Type} (B : I set T) :
  ( _ : I, True)
  ( i j, k, B k `<=` B i `&` B j)
  Filter (filter_from setT B).

Lemma filter_from_proper {I T : Type} (D : set I) (B : I set T) :
  Filter (filter_from D B)
  ( i, D i B i !=set0)
  ProperFilter (filter_from D B).

Lemma filter_bigI T (I : choiceType) (D : {fset I}) (f : I set T)
  (F : set (set T)) :
  Filter F ( i, i \in D F (f i))
  F (\bigcap_(i in [set i | i \in D]) f i).

Lemma filter_forall T (I : finType) (f : I set T) (F : set (set T)) :
    Filter F ( i : I, \ x \near F, f i x)
  \ x \near F, i, f i x.

Lemma filter_imply [T : Type] [P : Prop] [f : set T] [F : set (set T)] :
  Filter F (P \near F, f F) \near F, P f F.

Limits expressed with filters


Definition fmap {T U : Type} (f : T U) (F : set (set T)) :=
  [set P | F (f @^-1` P)].
Arguments fmap _ _ _ _ _ /.

Lemma fmapE {U V : Type} (f : U V)
  (F : set (set U)) (P : set V) : fmap f F P = F (f @^-1` P).

Notation "E @[ x --> F ]" :=
  (fmap (fun xE) [filter of F]) : classical_set_scope.
Notation "f @ F" := (fmap f [filter of F]) : classical_set_scope.
Global Instance fmap_filter T U (f : T U) (F : set (set T)) :
  Filter F Filter (f @ F).
Typeclasses Opaque fmap.

Global Instance fmap_proper_filter T U (f : T U) (F : set (set T)) :
  ProperFilter F ProperFilter (f @ F).
Definition fmap_proper_filter' := fmap_proper_filter.

Definition fmapi {T U : Type} (f : T set U) (F : set (set T)) :=
  [set P | \ x \near F, y, f x y P y].

Notation "E `@[ x --> F ]" :=
  (fmapi (fun xE) [filter of F]) : classical_set_scope.
Notation "f `@ F" := (fmapi f [filter of F]) : classical_set_scope.

Lemma fmapiE {U V : Type} (f : U set V)
  (F : set (set U)) (P : set V) :
  fmapi f F P = \ x \near F, y, f x y P y.

Global Instance fmapi_filter T U (f : T set U) (F : set (set T)) :
  infer {near F, is_totalfun f} Filter F Filter (f `@ F).

#[global] Typeclasses Opaque fmapi.

Global Instance fmapi_proper_filter
  T U (f : T U Prop) (F : set (set T)) :
  infer {near F, is_totalfun f}
  ProperFilter F ProperFilter (f `@ F).
Definition filter_map_proper_filter' := fmapi_proper_filter.

Lemma cvg_id T (F : set (set T)) : x @[x --> F] --> F.
Arguments cvg_id {T F}.

Lemma fmap_comp {A B C} (f : B C) (g : A B) F:
  Filter F (f \o g)%FUN @ F = f @ (g @ F).

Lemma appfilter U V (f : U V) (F : set (set U)) :
  f @ F = [set P : set _ | \ x \near F, P (f x)].

Lemma cvg_app U V (F G : set (set U)) (f : U V) :
  F --> G f @ F --> f @ G.
Arguments cvg_app {U V F G} _.

Lemma cvgi_app U V (F G : set (set U)) (f : U set V) :
  F --> G f `@ F --> f `@ G.

Lemma cvg_comp T U V (f : T U) (g : U V)
  (F : set (set T)) (G : set (set U)) (H : set (set V)) :
  f @ F `=>` G g @ G `=>` H g \o f @ F `=>` H.

Lemma cvgi_comp T U V (f : T U) (g : U set V)
  (F : set (set T)) (G : set (set U)) (H : set (set V)) :
  f @ F `=>` G g `@ G `=>` H g \o f `@ F `=>` H.

Lemma near_eq_cvg {T U} {F : set (set T)} {FF : Filter F} (f g : T U) :
  {near F, f =1 g} g @ F `=>` f @ F.

Lemma eq_cvg (T T' : Type) (F : set (set T)) (f g : T T') (x : set (set T')) :
  f =1 g (f @ F --> x) = (g @ F --> x).

Lemma eq_is_cvg (T T' : Type) (fT : filteredType T') (F : set (set T)) (f g : T T') :
  f =1 g [cvg (f @ F) in fT] = [cvg (g @ F) in fT].

Lemma neari_eq_loc {T U} {F : set (set T)} {FF : Filter F} (f g : T set U) :
  {near F, f =2 g} g `@ F `=>` f `@ F.

Lemma cvg_near_const (T U : Type) (f : T U) (F : set (set T)) (G : set (set U)) :
  Filter F ProperFilter G
  (\ y \near G, \ x \near F, f x = y) f @ F --> G.

Definition globally {T : Type} (A : set T) : set (set T) :=
   [set P : set T | x, A x P x].
Arguments globally {T} A _ /.

Lemma globally0 {T : Type} (A : set T) : globally set0 A.

Global Instance globally_filter {T : Type} (A : set T) :
  Filter (globally A).

Global Instance globally_properfilter {T : Type} (A : set T) a :
  infer (A a) ProperFilter (globally A).

Specific filters


Section frechet_filter.
Variable T : Type.

Definition frechet_filter := [set S : set T | finite_set (~` S)].

Global Instance frechet_properfilter : infinite_set [set: T]
  ProperFilter frechet_filter.

End frechet_filter.

Global Instance frechet_properfilter_nat : ProperFilter (@frechet_filter nat).

Section at_point.

Context {T : Type}.

Definition at_point (a : T) (P : set T) : Prop := P a.

Global Instance at_point_filter (a : T) : ProperFilter (at_point a).
Typeclasses Opaque at_point.

End at_point.

Filters for pairs

Global Instance filter_prod_filter T U (F : set (set T)) (G : set (set U)) :
  Filter F Filter G Filter (filter_prod F G).

Canonical prod_filter_on T U (F : filter_on T) (G : filter_on U) :=
  FilterType (filter_prod F G) (filter_prod_filter _ _).

Global Instance filter_prod_proper {T1 T2 : Type}
  {F : (T1 Prop) Prop} {G : (T2 Prop) Prop}
  {FF : ProperFilter F} {FG : ProperFilter G} :
  ProperFilter (filter_prod F G).
Definition filter_prod_proper' := @filter_prod_proper.

Lemma filter_prod1 {T U} {F : set (set T)} {G : set (set U)}
  {FG : Filter G} (P : set T) :
  (\ x \near F, P x) \ x \near F & _ \near G, P x.
Lemma filter_prod2 {T U} {F : set (set T)} {G : set (set U)}
  {FF : Filter F} (P : set U) :
  (\ y \near G, P y) \ _ \near F & y \near G, P y.

Program Definition in_filter_prod {T U} {F : set (set T)} {G : set (set U)}
  (P : in_filter F) (Q : in_filter G) : in_filter (filter_prod F G) :=
  @InFilter _ _ (fun xprop_of P x.1 prop_of Q x.2) _.

Lemma near_pair {T U} {F : set (set T)} {G : set (set U)}
      {FF : Filter F} {FG : Filter G}
      (P : in_filter F) (Q : in_filter G) x :
       prop_of P x.1 prop_of Q x.2 prop_of (in_filter_prod P Q) x.

Lemma cvg_fst {T U F G} {FG : Filter G} :
  (@fst T U) @ filter_prod F G --> F.

Lemma cvg_snd {T U F G} {FF : Filter F} :
  (@snd T U) @ filter_prod F G --> G.

Lemma near_map {T U} (f : T U) (F : set (set T)) (P : set U) :
  (\ y \near f @ F, P y) = (\ x \near F, P (f x)).

Lemma near_map2 {T T' U U'} (f : T U) (g : T' U')
      (F : set (set T)) (G : set (set T')) (P : U set U') :
  Filter F Filter G
  (\ y \near f @ F & y' \near g @ G, P y y') =
  (\ x \near F & x' \near G , P (f x) (g x')).

Lemma near_mapi {T U} (f : T set U) (F : set (set T)) (P : set U) :
  (\ y \near f `@ F, P y) = (\ x \near F, y, f x y P y).

Lemma filter_pair_set (T T' : Type) (F : set (set T)) (F' : set (set T')) :
   Filter F Filter F'
    (P : set T) (P' : set T') (Q : set (T × T')),
   ( x x', P x P' x' Q (x, x')) F P F' P'
   filter_prod F F' Q.

Lemma filter_pair_near_of (T T' : Type) (F : set (set T)) (F' : set (set T')) :
   Filter F Filter F'
    (P : @in_filter T F) (P' : @in_filter T' F') (Q : set (T × T')),
   ( x x', prop_of P x prop_of P' x' Q (x, x'))
   filter_prod F F' Q.

Tactic Notation "near=>" ident(x) ident(y) :=
  (apply: filter_pair_near_ofx y ? ?).
Tactic Notation "near" constr(F) "=>" ident(x) ident(y) :=
  apply: (have_near F); nearx y.

Module Export NearMap.
Definition near_simpl := (@near_simpl, @near_map, @near_mapi, @near_map2).
Ltac near_simpl := rewrite ?near_simpl.
End NearMap.

Lemma cvg_pair {T U V F} {G : set (set U)} {H : set (set V)}
  {FF : Filter F} {FG : Filter G} {FH : Filter H} (f : T U) (g : T V) :
  f @ F --> G g @ F --> H
  (f x, g x) @[x --> F] --> (G, H).

Lemma cvg_comp2 {T U V W}
  {F : set (set T)} {G : set (set U)} {H : set (set V)} {I : set (set W)}
  {FF : Filter F} {FG : Filter G} {FH : Filter H}
  (f : T U) (g : T V) (h : U V W) :
  f @ F --> G g @ F --> H
  h (fst x) (snd x) @[x --> (G, H)] --> I
  h (f x) (g x) @[x --> F] --> I.
Arguments cvg_comp2 {T U V W F G H I FF FG FH f g h} _ _ _.
Definition cvg_to_comp_2 := @cvg_comp2.

Restriction of a filter to a domain

Section within.
Context {T : Type}.
Implicit Types (D : set T) (F : set (set T)).

Definition within D F (P : set T) := {near F, D `<=` P}.
Arguments within : simpl never.

Lemma near_withinE D F (P : set T) :
  (\ x \near within D F, P x) = {near F, D `<=` P}.

Lemma withinT F D : Filter F within D F D.

Lemma near_withinT F D : Filter F \ x \near within D F, D x.

Lemma cvg_within {F} {FF : Filter F} D : within D F --> F.

Lemma withinET {F} {FF : Filter F} : within setT F = F.

End within.

Global Instance within_filter T D F : Filter F Filter (@within T D F).

#[global] Typeclasses Opaque within.

Canonical within_filter_on T D (F : filter_on T) :=
  FilterType (within D F) (within_filter _ _).

Definition subset_filter {T} (F : set (set T)) (D : set T) :=
  [set P : set {x | D x} | F [set x | Dx : D x, P (exist _ x Dx)]].
Arguments subset_filter {T} F D _.

Global Instance subset_filter_filter T F (D : set T) :
  Filter F Filter (subset_filter F D).
#[global] Typeclasses Opaque subset_filter.

Lemma subset_filter_proper {T F} {FF : Filter F} (D : set T) :
  ( P, F P ¬ ¬ x, D x P x)
  ProperFilter (subset_filter F D).

For using near on sets in a filter

Topological spaces


Module Topological.

Record mixin_of (T : Type) (nbhs : T set (set T)) := Mixin {
  open : set (set T) ;
  nbhs_pfilter : p : T, ProperFilter (nbhs p) ;
  nbhsE : p : T, nbhs p =
    [set A : set T | B : set T, [/\ open B, B p & B `<=` A] ] ;
  openE : open = [set A : set T | A `<=` nbhs^~ A ]
}.

Record class_of (T : Type) := Class {
  base : Filtered.class_of T T;
  mixin : mixin_of (Filtered.nbhs_op base)
}.

Section ClassDef.

Structure type := Pack { sort; _ : class_of sort }.
Variables (T : Type) (cT : type).
Definition class := let: Pack _ c := cT return class_of cT in c.

Definition clone c of phant_id class c := @Pack T c.
Let xT := let: Pack T _ := cT in T.
Notation xclass := (class : class_of xT).

Definition pack nbhs' (m : @mixin_of T nbhs') :=
  fun bT (b : Filtered.class_of T T) of phant_id (@Filtered.class T bT) b
  fun m' of phant_id m (m' : @mixin_of T (Filtered.nbhs_op b)) ⇒
  @Pack T (@Class _ b m').

Definition eqType := @Equality.Pack cT xclass.
Definition choiceType := @Choice.Pack cT xclass.
Definition pointedType := @Pointed.Pack cT xclass.
Definition filteredType := @Filtered.Pack cT cT xclass.

End ClassDef.

Module Exports.

Coercion sort : type >-> Sortclass.
Coercion base : class_of >-> Filtered.class_of.
Coercion mixin : class_of >-> mixin_of.
Coercion eqType : type >-> Equality.type.
Canonical eqType.
Coercion choiceType : type >-> Choice.type.
Canonical choiceType.
Coercion pointedType : type >-> Pointed.type.
Canonical pointedType.
Coercion filteredType : type >-> Filtered.type.
Canonical filteredType.
Notation topologicalType := type.
Notation TopologicalType T m := (@pack T _ m _ _ idfun _ idfun).
Notation TopologicalMixin := Mixin.
Notation "[ 'topologicalType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
  (at level 0, format "[ 'topologicalType' 'of' T 'for' cT ]") : form_scope.
Notation "[ 'topologicalType' 'of' T ]" := (@clone T _ _ id)
  (at level 0, format "[ 'topologicalType' 'of' T ]") : form_scope.

End Exports.

End Topological.

Export Topological.Exports.

Section Topological1.

Context {T : topologicalType}.

Definition open := Topological.open (Topological.class T).

Definition open_nbhs (p : T) (A : set T) := open A A p.

Definition basis (B : set (set T)) :=
  B `<=` open x, filter_from [set U | B U U x] id --> x.

Definition second_countable := exists2 B, countable B & basis B.

Global Instance nbhs_pfilter (p : T) : ProperFilter (nbhs p).
Typeclasses Opaque nbhs.

Lemma nbhs_filter (p : T) : Filter (nbhs p).

Canonical nbhs_filter_on (x : T) := FilterType (nbhs x) (@nbhs_filter x).

Lemma nbhsE (p : T) :
  nbhs p = [set A : set T | exists2 B : set T, open_nbhs p B & B `<=` A].

Lemma open_nbhsE (p : T) (A : set T) : open_nbhs p A = (open A nbhs p A).

Definition interior (A : set T) := (@nbhs _ T)^~ A.


Lemma interior_subset (A : set T) : A `<=` A.

Lemma openE : open = [set A : set T | A `<=` A].

Lemma nbhs_singleton (p : T) (A : set T) : nbhs p A A p.

Lemma nbhs_interior (p : T) (A : set T) : nbhs p A nbhs p A.

Lemma open0 : open set0.

Lemma openT : open setT.

Lemma openI (A B : set T) : open A open B open (A `&` B).

Lemma bigcup_open (I : Type) (D : set I) (f : I set T) :
  ( i, D i open (f i)) open (\bigcup_(i in D) f i).

Lemma openU (A B : set T) : open A open B open (A `|` B).

Lemma open_subsetE (A B : set T) : open A (A `<=` B) = (A `<=` B).

Lemma open_interior (A : set T) : open A.

Lemma interior_bigcup I (D : set I) (f : I set T) :
  \bigcup_(i in D) (f i)^° `<=` (\bigcup_(i in D) f i)^°.

Lemma open_nbhsT (p : T) : open_nbhs p setT.

Lemma open_nbhsI (p : T) (A B : set T) :
  open_nbhs p A open_nbhs p B open_nbhs p (A `&` B).

Lemma open_nbhs_nbhs (p : T) (A : set T) : open_nbhs p A nbhs p A.

Lemma interiorI (A B:set T): (A `&` B)^° = A `&` B.

End Topological1.

#[global] Hint Extern 0 (Filter (nbhs _)) ⇒
  solve [apply: nbhs_filter] : typeclass_instances.
#[global] Hint Extern 0 (ProperFilter (nbhs _)) ⇒
  solve [apply: nbhs_pfilter] : typeclass_instances.

Notation "A ^°" := (interior A) : classical_set_scope.

Notation continuous f := ( x, f%function @ x --> f%function x).

Lemma near_fun (T T' : topologicalType) (f : T T') (x : T) (P : T' Prop) :
    {for x, continuous f}
  (\ y \near f x, P y) (\near x, P (f x)).
Arguments near_fun {T T'} f x.

Lemma continuousP (S T : topologicalType) (f : S T) :
  continuous f A, open A open (f @^-1` A).

Lemma continuous_comp (R S T : topologicalType) (f : R S) (g : S T) x :
  {for x, continuous f} {for (f x), continuous g}
  {for x, continuous (g \o f)}.

Lemma open_comp {T U : topologicalType} (f : T U) (D : set U) :
  {in f @^-1` D, continuous f} open D open (f @^-1` D).

Lemma cvg_fmap {T: topologicalType} {U : topologicalType}
  (F : set (set T)) x (f : T U) :
   {for x, continuous f} F --> x f @ F --> f x.

Lemma near_join (T : topologicalType) (x : T) (P : set T) :
  (\near x, P x) \near x, \near x, P x.

Lemma near_bind (T : topologicalType) (P Q : set T) (x : T) :
  (\near x, (\near x, P x) Q x) (\near x, P x) \near x, Q x.

Lemma continuous_cvg {T : Type} {V U : topologicalType}
  (F : set (set T)) (FF : Filter F)
  (f : T V) (h : V U) (a : V) :
  {for a, continuous h}
  f @ F --> a (h \o f) @ F --> h a.

Lemma continuous_is_cvg {T : Type} {V U : topologicalType} [F : set (set T)]
  (FF : Filter F) (f : T V) (h : V U) :
  ( l, f x @[x --> F] --> l {for l, continuous h})
  cvg (f x @[x --> F]) cvg ((h \o f) x @[x --> F]).

Lemma continuous2_cvg {T : Type} {V W U : topologicalType}
  (F : set (set T)) (FF : Filter F)
  (f : T V) (g : T W) (h : V W U) (a : V) (b : W) :
  h z.1 z.2 @[z --> (a, b)] --> h a b
  f @ F --> a g @ F --> b (fun xh (f x) (g x)) @ F --> h a b.

Lemma cvg_near_cst (T : Type) (U : topologicalType)
  (l : U) (f : T U) (F : set (set T)) {FF : Filter F} :
  (\ x \near F, f x = l) f @ F --> l.
Arguments cvg_near_cst {T U} l {f F FF}.

Lemma is_cvg_near_cst (T : Type) (U : topologicalType)
  (l : U) (f : T U) (F : set (set T)) {FF : Filter F} :
  (\ x \near F, f x = l) cvg (f @ F).
Arguments is_cvg_near_cst {T U} l {f F FF}.

Lemma near_cst_continuous (T U : topologicalType)
  (l : U) (f : T U) (x : T) :
  (\ y \near x, f y = l) {for x, continuous f}.
Arguments near_cst_continuous {T U} l [f x].

Lemma cvg_cst (U : topologicalType) (x : U) (T : Type)
    (F : set (set T)) {FF : Filter F} :
  (fun _ : Tx) @ F --> x.
Arguments cvg_cst {U} x {T F FF}.
#[global] Hint Resolve cvg_cst : core.

Lemma is_cvg_cst (U : topologicalType) (x : U) (T : Type)
  (F : set (set T)) {FF : Filter F} :
  cvg ((fun _ : Tx) @ F).
Arguments is_cvg_cst {U} x {T F FF}.
#[global] Hint Resolve is_cvg_cst : core.

Lemma cst_continuous {T U : topologicalType} (x : U) :
  continuous (fun _ : Tx).

Section within_topologicalType.
Context {T : topologicalType} (A : set T).
Implicit Types B : set T.

Relation between globally and within A (nbhs x) to be combined with lemmas such as boundedP in normedtype.v
Lemma within_nbhsW (x : T) : A x within A (nbhs x) `=>` globally A.

Definition locally_of (P : set (set T) Prop) of phantom Prop (P (globally A))
  := x, A x P (within A (nbhs x)).

Lemma within_interior (x : T) : A x within A (nbhs x) = nbhs x.

Lemma within_subset B F : Filter F A `<=` B within A F `=>` within B F.

Lemma withinE F : Filter F
  within A F = [set U | exists2 V, F V & U `&` A = V `&` A].

Lemma fmap_within_eq {S : topologicalType} (F : set (set T)) (f g : T S) :
  Filter F {in A, f =1 g} f @ within A F --> g @ within A F.

End within_topologicalType.

Notation "[ 'locally' P ]" := (@locally_of _ _ _ (Phantom _ P)).

Topology defined by a filter


Section TopologyOfFilter.

Context {T : Type} {nbhs' : T set (set T)}.
Hypothesis (nbhs'_filter : p : T, ProperFilter (nbhs' p)).
Hypothesis (nbhs'_singleton : (p : T) (A : set T), nbhs' p A A p).
Hypothesis (nbhs'_nbhs' : (p : T) (A : set T), nbhs' p A nbhs' p (nbhs'^~ A)).

Definition open_of_nbhs := [set A : set T | A `<=` nbhs'^~ A].

Program Definition topologyOfFilterMixin : Topological.mixin_of nbhs' :=
  @Topological.Mixin T nbhs' open_of_nbhs _ _ _.

End TopologyOfFilter.

Topology defined by open sets


Section TopologyOfOpen.

Variable (T : Type) (op : set T Prop).
Hypothesis (opT : op setT).
Hypothesis (opI : (A B : set T), op A op B op (A `&` B)).
Hypothesis (op_bigU : (I : Type) (f : I set T),
  ( i, op (f i)) op (\bigcup_i f i)).

Definition nbhs_of_open (p : T) (A : set T) :=
   B, [/\ op B, B p & B `<=` A].

Program Definition topologyOfOpenMixin : Topological.mixin_of nbhs_of_open :=
  @Topological.Mixin T nbhs_of_open op _ _ _.

End TopologyOfOpen.

Topology defined by a base of open sets


Section TopologyOfBase.

Definition open_from I T (D : set I) (b : I set T) :=
  [set \bigcup_(i in D') b i | D' in subset^~ D].

Lemma open_fromT I T (D : set I) (b : I set T) :
  \bigcup_(i in D) b i = setT open_from D b setT.

Variable (I : pointedType) (T : Type) (D : set I) (b : I (set T)).
Hypothesis (b_cover : \bigcup_(i in D) b i = setT).
Hypothesis (b_join : i j t, D i D j b i t b j t
   k, [/\ D k, b k t & b k `<=` b i `&` b j]).

Program Definition topologyOfBaseMixin :=
  @topologyOfOpenMixin _ (open_from D b) (open_fromT b_cover) _ _.

End TopologyOfBase.

Section filter_supremums.

Global Instance smallest_filter_filter {T : Type} (F : set (set T)) :
  Filter (smallest Filter F).

Fixpoint filterI_iter {T : Type} (F : set (set T)) (n : nat) :=
  if n is m.+1
  then [set P `&` Q |
    P in filterI_iter F m & Q in filterI_iter F m]
  else setT |` F.

Lemma filterI_iter_sub {T : Type} (F : set (set T)) :
  {homo filterI_iter F : i j / (i j)%N >-> i `<=` j}.

Lemma filterI_iterE {T : Type} (F : set (set T)) :
  smallest Filter F = filter_from (\bigcup_n (filterI_iter F n)) id.

Topology defined by a subbase of open sets


Definition finI_from (I : choiceType) T (D : set I) (f : I set T) :=
  [set \bigcap_(i in [set` D']) f i |
    D' in [set A : {fset I} | {subset A D}]].

Lemma finI_from_cover (I : choiceType) T (D : set I) (f : I set T) :
  \bigcup_(A in finI_from D f) A = setT.

Lemma finI_from1 (I : choiceType) T (D : set I) (f : I set T) i :
  D i finI_from D f (f i).

Lemma finI_from_countable (I : pointedType) T (D : set I) (f : I set T) :
  countable D countable (finI_from D f).

Lemma finI_fromI {I : choiceType} T D (f : I set T) A B :
  finI_from D f A finI_from D f B finI_from D f (A `&` B) .

Lemma filterI_iter_finI {I : choiceType} T D (f : I set T) :
  finI_from D f = \bigcup_n (filterI_iter (f @` D) n).

Lemma smallest_filter_finI {T : choiceType} (D : set T) f :
  filter_from (finI_from D f) id = smallest (@Filter T) (f @` D).

End filter_supremums.

Section TopologyOfSubbase.

Variable (I : pointedType) (T : Type) (D : set I) (b : I set T).

Program Definition topologyOfSubbaseMixin :=
  @topologyOfBaseMixin _ _ (finI_from D b) id (finI_from_cover D b) _.

End TopologyOfSubbase.

Topology on nat
:TODO: ultimately nat could be replaced by any lattice
Definition eventually := filter_from setT (fun N[set n | (N n)%N]).
Notation "'\oo'" := eventually : classical_set_scope.

Canonical eventually_filter_source X :=
   @Filtered.Source X _ nat (fun ff @ \oo).

Global Instance eventually_filter : ProperFilter eventually.

Canonical eventually_filterType := FilterType eventually _.
Canonical eventually_pfilterType := PFilterType eventually (filter_not_empty _).

Lemma nbhs_infty_gt N : \ n \near \oo, (N < n)%N.
#[global] Hint Resolve nbhs_infty_gt : core.

Lemma nbhs_infty_ge N : \ n \near \oo, (N n)%N.

Lemma cvg_addnl N : addn N @ \oo --> \oo.

Lemma cvg_addnr N : addn^~ N --> \oo.

Lemma cvg_subnr N : subn^~ N --> \oo.

Lemma cvg_mulnl N : (N > 0)%N muln N --> \oo.

Lemma cvg_mulnr N :(N > 0)%N muln^~ N --> \oo.

Lemma cvg_divnr N : (N > 0)%N divn^~ N --> \oo.

Lemma near_inftyS (P : set nat) :
  (\ x \near \oo, P (S x)) (\ x \near \oo, P x).

Section infty_nat.
Local Open Scope nat_scope.

Let cvgnyP {F : set (set nat)} {FF : Filter F} : [<->
(* 0 *) F --> \oo;
(* 1 *) A, \ x \near F, A x;
(* 2 *) A, \ x \near F, A < x;
(* 3 *) \ A \near \oo, \ x \near F, A < x;
(* 4 *) \ A \near \oo, \ x \near F, A x ].

Section map.

Context {I : Type} {F : set (set I)} {FF : Filter F} (f : I nat).

Lemma cvgnyPge :
  f @ F --> \oo A, \ x \near F, A f x.

Lemma cvgnyPgt :
  f @ F --> \oo A, \ x \near F, A < f x.

Lemma cvgnyPgty :
  f @ F --> \oo \ A \near \oo, \ x \near F, A < f x.

Lemma cvgnyPgey :
  f @ F --> \oo \ A \near \oo, \ x \near F, A f x.

End map.

End infty_nat.

Topology on the product of two spaces

Topology on matrices

Weak topology by a function

Supremum of a family of topologies

Product topology


Section Product_Topology.

Variable (I : Type) (T : I topologicalType).

Definition product_topologicalType :=
  sup_topologicalType (fun iTopological.class
    (weak_topologicalType (fun f : dep_arrow_pointedType Tf i))).

End Product_Topology.

dnbhs

Definition dnbhs {T : topologicalType} (x : T) :=
  within (fun yy != x) (nbhs x).
Notation "x ^'" := (dnbhs x) : classical_set_scope.

Lemma dnbhsE (T : topologicalType) (x : T) : nbhs x = x^' `&` at_point x.

Global Instance dnbhs_filter {T : topologicalType} (x : T) : Filter x^'.
#[global] Typeclasses Opaque dnbhs.

Canonical dnbhs_filter_on (T : topologicalType) (x : T) :=
  FilterType x^' (dnbhs_filter _).

Lemma cvg_fmap2 (T U : Type) (f : T U):
   (F G : set (set T)), G `=>` F f @ G `=>` f @ F.

Lemma cvg_within_filter {T U} {f : T U} (F : set (set T)) {FF : (Filter F) }
  (G : set (set U)) : (D : set T), (f @ F) --> G (f @ within D F) --> G.

Lemma cvg_app_within {T} {U : topologicalType} (f : T U) (F : set (set T))
  (D : set T): Filter F cvg (f @ F) cvg (f @ within D F).

Lemma nbhs_dnbhs {T : topologicalType} (x : T) : x^' `=>` nbhs x.

meets

Lemma meets_openr {T : topologicalType} (F : set (set T)) (x : T) :
  F `#` nbhs x = F `#` open_nbhs x.

Lemma meets_openl {T : topologicalType} (F : set (set T)) (x : T) :
  nbhs x `#` F = open_nbhs x `#` F.

Lemma meets_globallyl T (A : set T) G :
  globally A `#` G = B, G B A `&` B !=set0.

Lemma meets_globallyr T F (B : set T) :
  F `#` globally B = A, F A A `&` B !=set0.

Lemma meetsxx T (F : set (set T)) (FF : Filter F) : F `#` F = ¬ (F set0).

Lemma proper_meetsxx T (F : set (set T)) (FF : ProperFilter F) : F `#` F.

Closed sets in topological spaces


Section Closed.

Context {T : topologicalType}.

Definition closure (A : set T) :=
  [set p : T | B, nbhs p B A `&` B !=set0].

Lemma closure0 : closure set0 = set0 :> set T.

Lemma closureEnbhs A : closure A = [set p | globally A `#` nbhs p].

Lemma closureEonbhs A : closure A = [set p | globally A `#` open_nbhs p].

Lemma subset_closure (A : set T) : A `<=` closure A.

Lemma closureI (A B : set T) : closure (A `&` B) `<=` closure A `&` closure B.

Definition limit_point E := [set t : T |
   U, nbhs t U y, [/\ y != t, E y & U y]].

Lemma limit_pointEnbhs E :
  limit_point E = [set p | globally (E `\ p) `#` nbhs p].

Lemma limit_pointEonbhs E :
  limit_point E = [set p | globally (E `\ p) `#` open_nbhs p].

Lemma subset_limit_point E : limit_point E `<=` closure E.

Lemma closure_limit_point E : closure E = E `|` limit_point E.

Definition closed (D : set T) := closure D `<=` D.

Lemma open_closedC (D : set T) : open D closed (~` D).

Lemma closed_bigI {I} (D : set I) (f : I set T) :
  ( i, D i closed (f i)) closed (\bigcap_(i in D) f i).

Lemma closedI (D E : set T) : closed D closed E closed (D `&` E).

Lemma closedT : closed setT.

Lemma closed0 : closed set0.

Lemma closedE : closed = [set A : set T | p, ¬ (\near p, ¬ A p) A p].

Lemma closed_openC (D : set T) : closed D open (~` D).

Lemma closedC (D : set T) : closed (~` D) = open D.

Lemma openC (D : set T) : open (~`D) = closed (D).

Lemma closed_closure (A : set T) : closed (closure A).

End Closed.

Lemma closed_comp {T U : topologicalType} (f : T U) (D : set U) :
  {in ~` f @^-1` D, continuous f} closed D closed (f @^-1` D).

Lemma closed_cvg {T} {V : topologicalType} {F} {FF : ProperFilter F}
    (u_ : T V) (A : V Prop) :
    (* BUG: elim does not see this as an elimination principle if A : set V *)
    closed A (\ n \near F, A (u_ n))
   l, u_ @ F --> l A l.
Arguments closed_cvg {T V F FF u_} _ _ _ _ _.

Lemma continuous_closedP (S T : topologicalType) (f : S T) :
  continuous f A, closed A closed (f @^-1` A).

Lemma closedU (T : topologicalType) (D E : set T) :
  closed D closed E closed (D `|` E).

Lemma closed_bigsetU (T : topologicalType) (I : eqType) (s : seq I)
    (F : I set T) : ( x, x \in s closed (F x))
  closed (\big[setU/set0]_(x <- s) F x).

Lemma closed_bigcup (T : topologicalType) (I : choiceType) (A : set I)
    (F : I set T) :
    finite_set A ( i, A i closed (F i))
  closed (\bigcup_(i in A) F i).

Section closure_lemmas.
Variable T : topologicalType.
Implicit Types E A B U : set T.

Lemma closure_subset A B : A `<=` B closure A `<=` closure B.

Lemma closureE A : closure A = smallest closed A.

Lemma closureC E :
  ~` closure E = \bigcup_(x in [set U | open U U `<=` ~` E]) x.

Lemma closure_id E : closed E E = closure E.

End closure_lemmas.

Compact sets


Section Compact.

Context {T : topologicalType}.

Definition cluster (F : set (set T)) := [set p : T | F `#` nbhs p].

Lemma cluster_nbhs t : cluster (nbhs t) t.

Lemma clusterEonbhs F : cluster F = [set p | F `#` open_nbhs p].

Lemma clusterE F : cluster F = \bigcap_(A in F) (closure A).

Lemma closureEcluster E : closure E = cluster (globally E).

Lemma cvg_cluster F G : F --> G cluster F `<=` cluster G.

Lemma cluster_cvgE F :
  Filter F
  cluster F = [set p | exists2 G, ProperFilter G & G --> p F `<=` G].

Lemma closureEcvg (E : set T):
  closure E =
  [set p | exists2 G, ProperFilter G & G --> p globally E `<=` G].

Definition compact A := (F : set (set T)),
  ProperFilter F F A A `&` cluster F !=set0.

Lemma compact0 : compact set0.

Lemma subclosed_compact (A B : set T) :
  closed A compact B A `<=` B compact A.

Definition hausdorff_space := p q : T, cluster (nbhs p) q p = q.

Typeclasses Opaque within.
Global Instance within_nbhs_proper (A : set T) p :
  infer (closure A p) ProperFilter (within A (nbhs p)).

Lemma compact_closed (A : set T) : hausdorff_space compact A closed A.

Lemma compact_set1 (x : T) : compact [set x].

End Compact.
Arguments hausdorff_space : clear implicits.

Section ClopenSets.
Implicit Type T : topologicalType.

Definition clopen {T} (A : set T) := open A closed A.

Lemma clopenI {T} (A B : set T) : clopen A clopen B clopen (A `&` B).

Lemma clopenU {T} (A B : set T) : clopen A clopen B clopen (A `|` B).

Lemma clopenC {T} (A B : set T) : clopen A clopen (~`A).

Lemma clopen0 {T} : @clopen T set0.

Lemma clopenT {T} : clopen [set: T].

Lemma clopen_comp {T U : topologicalType} (f : T U) (A : set U) :
 clopen A continuous f clopen (f @^-1` A).

End ClopenSets.

Section near_covering.
Context {X : topologicalType}.

Definition near_covering (K : set X) :=
   (I : Type) (F : set (set I)) (P : I X Prop),
  Filter F
  ( x, K x \ x' \near x & i \near F, P i x')
  \near F, K `<=` P F.

Let near_covering_compact : near_covering `<=` compact.

Let compact_near_covering : compact `<=` near_covering.

Lemma compact_near_coveringP A : compact A near_covering A.

End near_covering.

Section Tychonoff.

Class UltraFilter T (F : set (set T)) := {
  ultra_proper :> ProperFilter F ;
  max_filter : G : set (set T), ProperFilter G F `<=` G G = F
}.

Lemma ultra_cvg_clusterE (T : topologicalType) (F : set (set T)) :
  UltraFilter F cluster F = [set p | F --> p].

Lemma ultraFilterLemma T (F : set (set T)) :
  ProperFilter F G, UltraFilter G F `<=` G.

Lemma compact_ultra (T : topologicalType) :
  compact = [set A | F : set (set T),
  UltraFilter F F A A `&` [set p | F --> p] !=set0].

Lemma filter_image (T U : Type) (f : T U) (F : set (set T)) :
  Filter F f @` setT = setT Filter [set f @` A | A in F].

Lemma proper_image (T U : Type) (f : T U) (F : set (set T)) :
  ProperFilter F f @` setT = setT ProperFilter [set f @` A | A in F].

Lemma principal_filter_ultra {T : Type} (x : T) :
  UltraFilter (principal_filter x).

Lemma in_ultra_setVsetC T (F : set (set T)) (A : set T) :
  UltraFilter F F A F (~` A).

Lemma ultra_image (T U : Type) (f : T U) (F : set (set T)) :
  UltraFilter F f @` setT = setT UltraFilter [set f @` A | A in F].

Lemma tychonoff (I : eqType) (T : I topologicalType)
  (A : i, set (T i)) :
  ( i, compact (A i))
  @compact (product_topologicalType T)
    [set f : i, T i | i, A i (f i)].

End Tychonoff.

Lemma compact_cluster_set1 {T : topologicalType} (x : T) F V :
  hausdorff_space T compact V nbhs x V
  ProperFilter F F V cluster F = [set x] F --> x.

Section Precompact.

Context {X : topologicalType}.

Lemma compactU (A B : set X) : compact A compact B compact (A `|` B).

Lemma bigsetU_compact I (F : I set X) (s : seq I) (P : pred I) :
    ( i, P i compact (F i))
  compact (\big[setU/set0]_(i <- s | P i) F i).

The closed condition here is neccessary to make this definition work in a non-hausdorff setting.
Note we have to give the signature explicitly because there's no canonical topology associated with `K`. This should be cleaned up after HB port.

Lemma proj_continuous i : continuous (proj i : PK K i).

Lemma dfwith_continuous g (i : I) : continuous (dfwith g _ : K i PK).

Lemma proj_open i (A : set PK) : open A open (proj i @` A).

Lemma hausdorff_product :
  ( x, hausdorff_space (K x)) hausdorff_space PK.

End product_spaces.

Definition finI (I : choiceType) T (D : set I) (f : I set T) :=
   D' : {fset I}, {subset D' D}
  \bigcap_(i in [set i | i \in D']) f i !=set0.

Lemma finI_filter (I : choiceType) T (D : set I) (f : I set T) :
  finI D f ProperFilter (filter_from (finI_from D f) id).

Lemma filter_finI (T : pointedType) (F : set (set T)) (D : set (set T))
  (f : set T set T) :
  ProperFilter F ( A, D A F (f A)) finI D f.

Definition finite_subset_cover (I : choiceType) (D : set I)
    U (F : I set U) (A : set U) :=
  exists2 D' : {fset I}, {subset D' D} & A `<=` cover [set` D'] F.

Section Covers.

Variable T : topologicalType.

Definition cover_compact (A : set T) :=
   (I : choiceType) (D : set I) (f : I set T),
  ( i, D i open (f i)) A `<=` cover D f
  finite_subset_cover D f A.

Definition open_fam_of (A : set T) I (D : set I) (f : I set T) :=
  exists2 g : I set T, ( i, D i open (g i)) &
     i, D i f i = A `&` g i.

Lemma cover_compactE : cover_compact =
  [set A | (I : choiceType) (D : set I) (f : I set T),
    open_fam_of A D f
      A `<=` cover D f finite_subset_cover D f A].

Definition closed_fam_of (A : set T) I (D : set I) (f : I set T) :=
  exists2 g : I set T, ( i, D i closed (g i)) &
     i, D i f i = A `&` g i.

Lemma compact_In0 :
  compact = [set A | (I : choiceType) (D : set I) (f : I set T),
    closed_fam_of A D f finI D f \bigcap_(i in D) f i !=set0].

Lemma compact_cover : compact = cover_compact.

End Covers.

Lemma finite_compact {X : topologicalType} (A : set X) :
  finite_set A compact A.

Lemma clopen_countable {T : topologicalType}:
  compact [set: T] @second_countable T countable (@clopen T).

Section separated_topologicalType.
Variable (T : topologicalType).
Implicit Types x y : T.

Local Open Scope classical_set_scope.

Definition kolmogorov_space := x y, x != y
   A : set T, (A \in nbhs x y \in ~` A) (A \in nbhs y x \in ~` A).

Definition accessible_space := x y, x != y
   A : set T, open A x \in A y \in ~` A.

Lemma accessible_closed_set1 : accessible_space x, closed [set x].

Lemma accessible_kolmogorov : accessible_space kolmogorov_space.

Lemma accessible_finite_set_closed :
  accessible_space A : set T, finite_set A closed A.

Definition close x y : Prop := M, open_nbhs y M closure M x.

Lemma closeEnbhs x : close x = cluster (nbhs x).

Lemma closeEonbhs x : close x = [set y | open_nbhs x `#` open_nbhs y].

Lemma close_sym x y : close x y close y x.

Lemma cvg_close {F} {FF : ProperFilter F} x y : F --> x F --> y close x y.

Lemma close_refl x : close x x.
Hint Resolve close_refl : core.

Lemma close_cvg (F1 F2 : set (set T)) {FF2 : ProperFilter F2} :
  F1 --> F2 F2 --> F1 close (lim F1) (lim F2).

Lemma cvgx_close x y : x --> y close x y.

Lemma cvgi_close T' {F} {FF : ProperFilter F} (f : T' set T) (l l' : T) :
  {near F, is_fun f} f `@ F --> l f `@ F --> l' close l l'.
Definition cvg_toi_locally_close := @cvgi_close.

Lemma open_hausdorff : hausdorff_space T =
   x y, x != y
    exists2 AB, (x \in AB.1 y \in AB.2) &
                [/\ open AB.1, open AB.2 & AB.1 `&` AB.2 == set0].

Definition hausdorff_accessible : hausdorff_space T accessible_space.

Hypothesis sep : hausdorff_space T.

Lemma closeE x y : close x y = (x = y).

Lemma close_eq x y : close x y x = y.

Lemma cvg_unique {F} {FF : ProperFilter F} : is_subset1 [set x : T | F --> x].

Lemma cvg_eq x y : x --> y x = y.

Lemma lim_id x : lim x = x.

Lemma cvg_lim {U : Type} {F} {FF : ProperFilter F} (f : U T) (l : T) :
  f @ F --> l lim (f @ F) = l.

Lemma lim_near_cst {U} {F} {FF : ProperFilter F} (l : T) (f : U T) :
   (\ x \near F, f x = l) lim (f @ F) = l.

Lemma lim_cst {U} {F} {FF : ProperFilter F} (k : T) :
   lim ((fun _ : Uk) @ F) = k.

Lemma cvgi_unique {U : Type} {F} {FF : ProperFilter F} (f : U set T) :
  {near F, is_fun f} is_subset1 [set x : T | f `@ F --> x].

Lemma cvgi_lim {U} {F} {FF : ProperFilter F} (f : U T Prop) (l : T) :
  F (fun x : Uis_subset1 (f x))
  f `@ F --> l lim (f `@ F) = l.

End separated_topologicalType.

#[deprecated(since="mathcomp-analysis 0.6.0", note="renamed to `cvg_lim`")]
Notation cvg_map_lim := cvg_lim.
#[deprecated(since="mathcomp-analysis 0.6.0", note="renamed to `cvgi_lim`")]
Notation cvgi_map_lim := cvgi_lim.

Section connected_sets.
Variable T : topologicalType.
Implicit Types A B C D : set T.

Definition connected A :=
   B, B !=set0 (exists2 C, open C & B = A `&` C)
  (exists2 C, closed C & B = A `&` C) B = A.

Lemma connected0 : connected (@set0 T).

Definition separated A B :=
  (closure A) `&` B = set0 A `&` (closure B) = set0.

Lemma separatedC A B : separated A B = separated B A.

Lemma separated_disjoint A B : separated A B A `&` B = set0.

Lemma connectedPn A : ¬ connected A
   E : bool set T, [/\ b, E b !=set0,
    A = E false `|` E true & separated (E false) (E true)].

Lemma connectedP A : connected A
   E : bool set T, ¬ [/\ b, E b !=set0,
    A = E false `|` E true & separated (E false) (E true)].

Lemma connected_subset A B C : separated A B C `<=` A `|` B
  connected C C `<=` A C `<=` B.

Lemma connected1 x : connected [set x].
Hint Resolve connected1 : core.

Lemma bigcup_connected I (A : I set T) (P : I Prop) :
  \bigcap_(i in P) (A i) !=set0 ( i, P i connected (A i))
  connected (\bigcup_(i in P) (A i)).

Lemma connectedU A B : A `&` B !=set0 connected A connected B
   connected (A `|` B).

Lemma connected_closure A : connected A connected (closure A).

Definition connected_component (A : set T) (x : T) :=
  \bigcup_(A in [set C : set T | [/\ C x, C `<=` A & connected C]]) A.

Lemma component_connected A x : connected (connected_component A x).

Lemma connected_component_sub A x : connected_component A x `<=` A.

Lemma connected_component_id A x :
  A x connected A connected_component A x = A.

Lemma connected_component_out A x :
  ¬ A x connected_component A x = set0.

Lemma connected_component_max A B x : B x B `<=` A
  connected B B `<=` connected_component A x.

Lemma connected_component_refl A x : A x connected_component A x x.

Lemma connected_component_cover A :
  \bigcup_(A in connected_component A @` A) A = A.

Lemma connected_component_sym A x y :
  connected_component A x y connected_component A y x.

Lemma connected_component_trans A y x z :
    connected_component A x y connected_component A y z
  connected_component A x z.

Lemma same_connected_component A x y : connected_component A x y
  connected_component A x = connected_component A y.

Lemma component_closed A x : closed A closed (connected_component A x).

Lemma clopen_separatedP A : clopen A separated A (~` A).

End connected_sets.
Arguments connected {T}.
Arguments connected_component {T}.
Section DiscreteTopology.
Section DiscreteMixin.
Context {X : Type}.

Lemma discrete_sing (p : X) (A : set X) : principal_filter p A A p.

Lemma discrete_nbhs (p : X) (A : set X) :
  principal_filter p A principal_filter p (principal_filter^~ A).

Definition discrete_topological_mixin :=
  topologyOfFilterMixin principal_filter_proper discrete_sing discrete_nbhs.

End DiscreteMixin.

Definition discrete_space (X : topologicalType) :=
  @nbhs X _ = @principal_filter X.

Context {X : topologicalType} {dsc: discrete_space X}.

Lemma discrete_open (A : set X) : open A.

Lemma discrete_set1 (x : X) : nbhs x [set x].

Lemma discrete_closed (A : set X) : closed A.

Lemma discrete_cvg (F : set (set X)) (x : X) :
  Filter F F --> x F [set x].

Lemma discrete_hausdorff : hausdorff_space X.

Canonical bool_discrete_topology : topologicalType :=
  TopologicalType bool discrete_topological_mixin.

Lemma discrete_bool : discrete_space bool_discrete_topology.

Lemma bool_compact : compact [set: bool].

End DiscreteTopology.

#[global] Hint Resolve discrete_bool : core.

Section perfect_sets.

Implicit Types (T : topologicalType).

Definition perfect_set {T} (A : set T) := closed A limit_point A = A.

Lemma perfectTP {T} : perfect_set [set: T] x : T, ¬ open [set x].

Lemma perfect_prod {I : Type} (i : I) (K : I topologicalType) :
  perfect_set [set: K i] perfect_set [set: product_topologicalType K].

Lemma perfect_diagonal (K : nat_topologicalType topologicalType) :
  ( i, (xy: K i × K i), xy.1 != xy.2)
  perfect_set [set: product_topologicalType K].

End perfect_sets.

Section totally_disconnected.
Implicit Types T : topologicalType.

Definition totally_disconnected {T} (A : set T) :=
   x, A x connected_component A x = [set x].

Definition zero_dimensional T :=
  ( x y, x != y U : set T, [/\ clopen U, U x & ¬ U y]).

Lemma zero_dimension_prod (I : choiceType) (T : I topologicalType) :
  ( i, zero_dimensional (T i))
  zero_dimensional (product_topologicalType T).

Lemma discrete_zero_dimension {T} : discrete_space T zero_dimensional T.

Lemma zero_dimension_totally_disconnected {T} :
  zero_dimensional T totally_disconnected [set: T].

Lemma totally_disconnected_cvg {T : topologicalType} (x : T) :
  hausdorff_space T zero_dimensional T compact [set: T]
  filter_from [set D : set T | D x clopen D] id --> x.

End totally_disconnected.

Section set_nbhs.

Context {T : topologicalType} (A : set T).
Definition set_nbhs := \bigcap_(x in A) (nbhs x).

Global Instance set_nbhs_filter : Filter set_nbhs.

Global Instance set_nbhs_pfilter : A!=set0 ProperFilter set_nbhs.

Lemma set_nbhsP (B : set T) :
   set_nbhs B ( C, [/\ open C, A `<=` C & C `<=` B]).

End set_nbhs.

Uniform spaces




Definition nbhs_ {T T'} (ent : set (set (T × T'))) (x : T) :=
  filter_from ent (fun Ato_set A x).

Lemma nbhs_E {T T'} (ent : set (set (T × T'))) x :
  nbhs_ ent x = filter_from ent (fun Ato_set A x).

Module Uniform.

Record mixin_of (M : Type) (nbhs : M set (set M)) := Mixin {
  entourage : (M × M Prop) Prop ;
  entourage_filter : Filter entourage ;
  entourage_refl : A, entourage A [set xy | xy.1 = xy.2] `<=` A ;
  entourage_inv : A, entourage A entourage (A^-1)%classic ;
  entourage_split_ex :
     A, entourage A exists2 B, entourage B & B \; B `<=` A ;
  nbhsE : nbhs = nbhs_ entourage
}.

Record class_of (M : Type) := Class {
  base : Topological.class_of M;
  mixin : mixin_of (Filtered.nbhs_op base)
}.

Section ClassDef.

Structure type := Pack { sort; _ : class_of sort }.
Variables (T : Type) (cT : type).
Definition class := let: Pack _ c := cT return class_of cT in c.

Definition clone c of phant_id class c := @Pack T c.
Let xT := let: Pack T _ := cT in T.
Notation xclass := (class : class_of xT).

Definition pack nbhs (m : @mixin_of T nbhs) :=
  fun bT (b : Topological.class_of T) of phant_id (@Topological.class bT) b
  fun m' of phant_id m (m' : @mixin_of T (Filtered.nbhs_op b)) ⇒
  @Pack T (@Class _ b m').

Definition eqType := @Equality.Pack cT xclass.
Definition choiceType := @Choice.Pack cT xclass.
Definition pointedType := @Pointed.Pack cT xclass.
Definition filteredType := @Filtered.Pack cT cT xclass.
Definition topologicalType := @Topological.Pack cT xclass.

End ClassDef.

Module Exports.

Coercion sort : type >-> Sortclass.
Coercion base : class_of >-> Topological.class_of.
Coercion mixin : class_of >-> mixin_of.
Coercion eqType : type >-> Equality.type.
Canonical eqType.
Coercion choiceType : type >-> Choice.type.
Canonical choiceType.
Coercion pointedType : type >-> Pointed.type.
Canonical pointedType.
Coercion filteredType : type >-> Filtered.type.
Canonical filteredType.
Coercion topologicalType : type >-> Topological.type.
Canonical topologicalType.
Notation uniformType := type.
Notation UniformType T m := (@pack T _ m _ _ idfun _ idfun).
Notation UniformMixin := Mixin.
Notation "[ 'uniformType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
  (at level 0, format "[ 'uniformType' 'of' T 'for' cT ]") : form_scope.
Notation "[ 'uniformType' 'of' T ]" := (@clone T _ _ id)
  (at level 0, format "[ 'uniformType' 'of' T ]") : form_scope.

End Exports.

End Uniform.

Export Uniform.Exports.

Section UniformTopology.

Program Definition topologyOfEntourageMixin (T : Type)
  (nbhs : T set (set T)) (m : Uniform.mixin_of nbhs) :
  Topological.mixin_of nbhs := topologyOfFilterMixin _ _ _.

End UniformTopology.

Definition entourage {M : uniformType} := Uniform.entourage (Uniform.class M).

Lemma nbhs_entourageE {M : uniformType} : nbhs_ (@entourage M) = nbhs.

Lemma entourage_sym {X Y : Type} E (x : X) (y : Y) :
  E (x, y) (E ^-1)%classic (y, x).

Lemma filter_from_entourageE {M : uniformType} x :
  filter_from (@entourage M) (fun Ato_set A x) = nbhs x.

Module Export NbhsEntourage.
Definition nbhs_simpl :=
  (nbhs_simpl,@filter_from_entourageE,@nbhs_entourageE).
End NbhsEntourage.

Lemma nbhsP {M : uniformType} (x : M) P : nbhs x P nbhs_ entourage x P.

Lemma filter_inv {T : Type} (F : set (set (T × T))) :
  Filter F Filter [set (V^-1)%classic | V in F].

Section uniformType1.
Context {M : uniformType}.

Lemma entourage_refl (A : set (M × M)) x : entourage A A (x, x).

Global Instance entourage_pfilter : ProperFilter (@entourage M).

Lemma entourageT : entourage [set: M × M].

Lemma entourage_inv (A : set (M × M)) : entourage A entourage (A^-1)%classic.

Lemma entourage_split_ex (A : set (M × M)) :
  entourage A exists2 B, entourage B & B \; B `<=` A.

Definition split_ent (A : set (M × M)) :=
  get (entourage `&` [set B | B \; B `<=` A]).

Lemma split_entP (A : set (M × M)) : entourage A
  entourage (split_ent A) split_ent A \; split_ent A `<=` A.

Lemma entourage_split_ent (A : set (M × M)) : entourage A
  entourage (split_ent A).

Lemma subset_split_ent (A : set (M × M)) : entourage A
  split_ent A \; split_ent A `<=` A.

Lemma entourage_split (z x y : M) A : entourage A
  split_ent A (x,z) split_ent A (z,y) A (x,y).

Lemma nbhs_entourage (x : M) A : entourage A nbhs x (to_set A x).

Lemma cvg_entourageP F (FF : Filter F) (p : M) :
  F --> p A, entourage A \ q \near F, A (p, q).

Lemma cvg_entourage {F} {FF : Filter F} (y : M) :
  F --> y A, entourage A \ y' \near F, A (y,y').

Lemma cvg_app_entourageP T (f : T M) F (FF : Filter F) p :
  f @ F --> p A, entourage A \ t \near F, A (p, f t).

Lemma entourage_invI (E : set (M × M)) :
  entourage E entourage (E `&` E^-1)%classic.

Lemma split_ent_subset (E : set (M × M)) : entourage E split_ent E `<=` E.

End uniformType1.

#[global]
Hint Extern 0 (entourage (split_ent _)) ⇒ exact: entourage_split_ent : core.
#[global]
Hint Extern 0 (entourage (get _)) ⇒ exact: entourage_split_ent : core.
#[global]
Hint Extern 0 (entourage (_^-1)%classic) ⇒ exact: entourage_inv : core.
Arguments entourage_split {M} z {x y A}.
#[global]
Hint Extern 0 (nbhs _ (to_set _ _)) ⇒ exact: nbhs_entourage : core.

Lemma ent_closure {M : uniformType} (x : M) E : entourage E
  closure (to_set (split_ent E) x) `<=` to_set E x.

Lemma continuous_withinNx {U V : uniformType} (f : U V) x :
  {for x, continuous f} f @ x^' --> f x.

Definition countable_uniformity (T : uniformType) :=
   R : set (set (T × T)), [/\
    countable R,
    R `<=` entourage &
     P, entourage P exists2 Q, R Q & Q `<=` P].

Lemma countable_uniformityP {T : uniformType} :
  countable_uniformity T exists2 f : nat set (T × T),
    ( A, entourage A N, f N `<=` A) &
    ( n, entourage (f n)).

Section uniform_closeness.

Variable (U : uniformType).

Lemma open_nbhs_entourage (x : U) (A : set (U × U)) :
  entourage A open_nbhs x (to_set A x)^°.

Lemma entourage_close (x y : U) : close x y = A, entourage A A (x, y).

Lemma close_trans (y x z : U) : close x y close y z close x z.

Lemma close_cvgxx (x y : U) : close x y x --> y.

Lemma cvg_closeP (F : set (set U)) (l : U) : ProperFilter F
  F --> l ([cvg F in U] close (lim F) l).

End uniform_closeness.

Definition unif_continuous (U V : uniformType) (f : U V) :=
  (fun xy(f xy.1, f xy.2)) @ entourage --> entourage.

product of two uniform spaces
matrices

Section matrix_Uniform.

Variables (m n : nat) (T : uniformType).

Implicit Types A : set ('M[T]_(m, n) × 'M[T]_(m, n)).

Definition mx_ent :=
  filter_from
  [set P : 'I_m 'I_n set (T × T) | i j, entourage (P i j)]
  (fun P[set MN : 'M[T]_(m, n) × 'M[T]_(m, n) |
     i j, P i j (MN.1 i j, MN.2 i j)]).

Lemma mx_ent_filter : Filter mx_ent.

Lemma mx_ent_refl A : mx_ent A [set MN | MN.1 = MN.2] `<=` A.

Lemma mx_ent_inv A : mx_ent A mx_ent (A^-1)%classic.

Lemma mx_ent_split A : mx_ent A exists2 B, mx_ent B & B \; B `<=` A.

Lemma mx_ent_nbhsE : nbhs = nbhs_ mx_ent.

Definition matrix_uniformType_mixin :=
  Uniform.Mixin mx_ent_filter mx_ent_refl mx_ent_inv mx_ent_split
  mx_ent_nbhsE.

Canonical matrix_uniformType :=
  UniformType 'M[T]_(m, n) matrix_uniformType_mixin.

End matrix_Uniform.

Lemma cvg_mx_entourageP (T : uniformType) m n (F : set (set 'M[T]_(m,n)))
  (FF : Filter F) (M : 'M[T]_(m,n)) :
  F --> M
   A, entourage A \ N \near F,
   i j, A (M i j, (N : 'M[T]_(m,n)) i j).

Functional metric spaces

PseudoMetric spaces defined using balls


Definition entourage_ {R : numDomainType} {T T'} (ball : T R set T') :=
  @filter_from R _ [set x | 0 < x] (fun e[set xy | ball xy.1 e xy.2]).

Lemma entourage_E {R : numDomainType} {T T'} (ball : T R set T') :
  entourage_ ball =
  @filter_from R _ [set x | 0 < x] (fun e[set xy | ball xy.1 e xy.2]).

Definition map_pair {S U} (f : S U) (x : (S × S)) : (U × U) :=
  (f x.1, f x.2).

Section weak_uniform.

Variable (pS : pointedType) (U : uniformType) (f : pS U).

Let S := weak_topologicalType f.

Definition weak_ent : set (set (S × S)) :=
  filter_from (@entourage U) (fun V(map_pair f)@^-1` V).

Lemma weak_ent_filter : Filter weak_ent.

Lemma weak_ent_refl A : weak_ent A [set fg | fg.1 = fg.2] `<=` A.

Lemma weak_ent_inv A : weak_ent A weak_ent (A^-1)%classic.

Lemma weak_ent_split A : weak_ent A exists2 B, weak_ent B & B \; B `<=` A.

Lemma weak_ent_nbhs : nbhs = nbhs_ weak_ent.

Definition weak_uniform_mixin :=
  @UniformMixin S nbhs weak_ent
    weak_ent_filter weak_ent_refl weak_ent_inv weak_ent_split weak_ent_nbhs.

Definition weak_uniformType :=
  UniformType S weak_uniform_mixin.

End weak_uniform.

Section sup_uniform.

Variable (T : pointedType) (Ii : Type) (Tc : Ii Uniform.class_of T).

Let I : choiceType := classicType_choiceType Ii.
Let TS := fun iUniform.Pack (Tc i).
Let Tt := @sup_topologicalType T I Tc.
Let ent_of (p : I × set (T × T)) := `[< @entourage (TS p.1) p.2>].
Let IEnt := ChoiceType {p : (I × set (T × T)) | ent_of p} (sig_choiceMixin _).


Definition sup_ent : (set (set (T × T))) :=
  filter_from (finI_from [set: IEnt] (fun p(projT1 p).2)) id.

Ltac IEntP := move⇒ [[ /= + + /[dup] /asboolP]].

Definition sup_ent_filter : Filter sup_ent.

Lemma sup_ent_refl A : sup_ent A [set fg | fg.1 = fg.2] `<=` A.

Lemma sup_ent_inv A : sup_ent A sup_ent (A^-1)%classic.

Lemma sup_ent_split A : sup_ent A exists2 B, sup_ent B & B \; B `<=` A.

Lemma sup_ent_nbhs : @nbhs Tt Tt = nbhs_ sup_ent.

Definition sup_uniform_mixin:=
  @UniformMixin Tt nbhs
    sup_ent sup_ent_filter sup_ent_refl sup_ent_inv sup_ent_split sup_ent_nbhs.

Definition sup_uniformType := UniformType Tt sup_uniform_mixin.

Lemma countable_sup_ent :
  countable [set: Ii] ( n, countable_uniformity (TS n))
  countable_uniformity sup_uniformType.

End sup_uniform.

Section product_uniform.

Variable (I : choiceType) (T : I uniformType).

Definition product_uniformType :=
  sup_uniformType (fun iUniform.class
    (weak_uniformType (fun f : dep_arrow_pointedType Tf i))).

End product_uniform.

Section discrete_uniform.

Context {T : topologicalType} {dsc: discrete_space T}.

Definition discrete_ent : set (set (T × T)) :=
  globally (range (fun x(x, x))).

Program Definition discrete_uniform_mixin :=
  @UniformMixin T nbhs discrete_ent _ _ _ _ _.

Definition discrete_uniformType := UniformType T discrete_uniform_mixin.

End discrete_uniform.

Module PseudoMetric.

Record mixin_of (R : numDomainType) (M : Type)
    (entourage : set (set (M × M))) := Mixin {
  ball : M R M Prop ;
  ball_center : x (e : R), 0 < e ball x e x ;
  ball_sym : x y (e : R), ball x e y ball y e x ;
  ball_triangle :
     x y z e1 e2, ball x e1 y ball y e2 z ball x (e1 + e2) z;
  entourageE : entourage = entourage_ ball
}.

Record class_of (R : numDomainType) (M : Type) := Class {
  base : Uniform.class_of M;
  mixin : mixin_of R (Uniform.entourage base)
}.

Section ClassDef.
Variable R : numDomainType.
Structure type := Pack { sort; _ : class_of R sort }.
Variables (T : Type) (cT : type).
Definition class := let: Pack _ c := cT return class_of R cT in c.

Definition clone c of phant_id class c := @Pack T c.
Let xT := let: Pack T _ := cT in T.
Notation xclass := (class : class_of R xT).

Definition pack ent (m : @mixin_of R T ent) :=
  fun bT (b : Uniform.class_of T) of phant_id (@Uniform.class bT) b
  fun m' of phant_id m (m' : @mixin_of R T (Uniform.entourage b)) ⇒
  @Pack T (@Class R _ b m').

Definition eqType := @Equality.Pack cT xclass.
Definition choiceType := @Choice.Pack cT xclass.
Definition pointedType := @Pointed.Pack cT xclass.
Definition filteredType := @Filtered.Pack cT cT xclass.
Definition topologicalType := @Topological.Pack cT xclass.
Definition uniformType := @Uniform.Pack cT xclass.

End ClassDef.

Module Exports.

Coercion sort : type >-> Sortclass.
Coercion base : class_of >-> Uniform.class_of.
Coercion mixin : class_of >-> mixin_of.
Coercion eqType : type >-> Equality.type.
Canonical eqType.
Coercion choiceType : type >-> Choice.type.
Canonical choiceType.
Coercion pointedType : type >-> Pointed.type.
Canonical pointedType.
Coercion filteredType : type >-> Filtered.type.
Canonical filteredType.
Coercion topologicalType : type >-> Topological.type.
Canonical topologicalType.
Coercion uniformType : type >-> Uniform.type.
Canonical uniformType.
Notation pseudoMetricType := type.
Notation PseudoMetricType T m := (@pack _ T _ m _ _ idfun _ idfun).
Notation PseudoMetricMixin := Mixin.
Notation "[ 'pseudoMetricType' R 'of' T 'for' cT ]" := (@clone R T cT _ idfun)
  (at level 0, format "[ 'pseudoMetricType' R 'of' T 'for' cT ]") : form_scope.
Notation "[ 'pseudoMetricType' R 'of' T ]" := (@clone R T _ _ id)
  (at level 0, format "[ 'pseudoMetricType' R 'of' T ]") : form_scope.

End Exports.

End PseudoMetric.

Export PseudoMetric.Exports.

Section PseudoMetricUniformity.

Let ball_le (R : numDomainType) (M : Type) (ent : set (set (M × M)))
    (m : PseudoMetric.mixin_of R ent) :
   (x : M), {homo PseudoMetric.ball m x : e1 e2 / e1 e2 >-> e1 `<=` e2}.

Program Definition uniformityOfBallMixin (R : numFieldType) (T : Type)
  (ent : set (set (T × T))) (nbhs : T set (set T)) (nbhsE : nbhs = nbhs_ ent)
  (m : PseudoMetric.mixin_of R ent) : Uniform.mixin_of nbhs :=
  UniformMixin _ _ _ _ nbhsE.

End PseudoMetricUniformity.

Definition ball {R : numDomainType} {M : pseudoMetricType R} :=
  PseudoMetric.ball (PseudoMetric.class M).

Lemma entourage_ballE {R : numDomainType} {M : pseudoMetricType R}
  : entourage_ (@ball R M) = entourage.

Lemma entourage_from_ballE {R : numDomainType} {M : pseudoMetricType R} :
  @filter_from R _ [set x : R | 0 < x]
    (fun e[set xy | @ball R M xy.1 e xy.2]) = entourage.

Lemma entourage_ball {R : numDomainType} (M : pseudoMetricType R)
  (e : {posnum R}) : entourage [set xy : M × M | ball xy.1 e%:num xy.2].
#[global] Hint Resolve entourage_ball : core.

Definition nbhs_ball_ {R : numDomainType} {T T'} (ball : T R set T')
  (x : T) := @filter_from R _ [set e | e > 0] (ball x).

Definition nbhs_ball {R : numDomainType} {M : pseudoMetricType R} :=
  nbhs_ball_ (@ball R M).

Lemma nbhs_ballE {R : numDomainType} {M : pseudoMetricType R} : (@nbhs_ball R M) = nbhs.

Lemma filter_from_ballE {R : numDomainType} {M : pseudoMetricType R} x :
  @filter_from R _ [set x : R | 0 < x] (@ball R M x) = nbhs x.

Module Export NbhsBall.
Definition nbhs_simpl := (nbhs_simpl,@filter_from_ballE,@nbhs_ballE).
End NbhsBall.

Lemma nbhs_ballP {R : numDomainType} {M : pseudoMetricType R} (x : M) P :
  nbhs x P nbhs_ball x P.

Lemma ball_center {R : numDomainType} (M : pseudoMetricType R) (x : M)
  (e : {posnum R}) : ball x e%:num x.
#[global] Hint Resolve ball_center : core.

Section pseudoMetricType_numDomainType.
Context {R : numDomainType} {M : pseudoMetricType R}.

Lemma ballxx (x : M) (e : R) : 0 < e ball x e x.

Lemma ball_sym (x y : M) (e : R) : ball x e y ball y e x.

Lemma ball_symE (x y : M) (e : R) : ball x e y = ball y e x.

Lemma ball_triangle (y x z : M) (e1 e2 : R) :
  ball x e1 y ball y e2 z ball x (e1 + e2) z.

Lemma nbhsx_ballx (x : M) (eps : {posnum R}) : nbhs x (ball x eps%:num).

Lemma open_nbhs_ball (x : M) (eps : {posnum R}) : open_nbhs x ((ball x eps%:num)^°).

Lemma le_ball (x : M) (e1 e2 : R) : e1 e2 ball x e1 `<=` ball x e2.

Global Instance entourage_proper_filter : ProperFilter (@entourage M).

Lemma near_ball (y : M) (eps : {posnum R}) :
   \ y' \near y, ball y eps%:num y'.

Lemma fcvg_ballP {F} {FF : Filter F} (y : M) :
  F --> y eps : R, 0 < eps \ y' \near F, ball y eps y'.

Lemma __deprecated__cvg_ballPpos {F} {FF : Filter F} (y : M) :
  F --> y eps : {posnum R}, \ y' \near F, ball y eps%:num y'.
#[deprecated(since="mathcomp-analysis 0.6.0",
  note="use a combination of `cvg_ballP` and `posnumP`")]
Notation cvg_ballPpos := __deprecated__cvg_ballPpos.

Lemma fcvg_ball {F} {FF : Filter F} (y : M) :
  F --> y eps : R, 0 < eps \ y' \near F, ball y eps y'.

Lemma cvg_ballP {T} {F} {FF : Filter F} (f : T M) y :
  f @ F --> y eps : R, 0 < eps \ x \near F, ball y eps (f x).

Lemma cvg_ball {T} {F} {FF : Filter F} (f : T M) y :
  f @ F --> y eps : R, 0 < eps \ x \near F, ball y eps (f x).

Lemma cvgi_ballP T {F} {FF : Filter F} (f : T M Prop) y :
  f `@ F --> y
   eps : R, 0 < eps \ x \near F, z, f x z ball y eps z.
Definition cvg_toi_locally := @cvgi_ballP.

Lemma cvgi_ball T {F} {FF : Filter F} (f : T M Prop) y :
  f `@ F --> y
   eps : R, 0 < eps F [set x | z, f x z ball y eps z].

End pseudoMetricType_numDomainType.
#[global] Hint Resolve nbhsx_ballx : core.
#[global] Hint Resolve close_refl : core.
Arguments close_cvg {T} F1 F2 {FF2} _.

#[deprecated(since="mathcomp-analysis 0.6.0", note="renamed `cvg_ball`")]
Notation app_cvg_locally := cvg_ball.

Section pseudoMetricType_numFieldType.
Context {R : numFieldType} {M : pseudoMetricType R}.

Lemma ball_split (z x y : M) (e : R) :
  ball x (e / 2) z ball z (e / 2) y ball x e y.

Lemma ball_splitr (z x y : M) (e : R) :
  ball z (e / 2) x ball z (e / 2) y ball x e y.

Lemma ball_splitl (z x y : M) (e : R) :
  ball x (e / 2) z ball y (e / 2) z ball x e y.

Lemma ball_close (x y : M) :
  close x y = eps : {posnum R}, ball x eps%:num y.

End pseudoMetricType_numFieldType.

Section ball_hausdorff.
Variables (R : numDomainType) (T : pseudoMetricType R).

Lemma ball_hausdorff : hausdorff_space T =
   (a b : T), a != b
   r : {posnum R} × {posnum R},
    ball a r.1%:num `&` ball b r.2%:num == set0.
End ball_hausdorff.

Section entourages.
Variable R : numDomainType.
Lemma unif_continuousP (U V : pseudoMetricType R) (f : U V) :
  unif_continuous f
   e, e > 0 exists2 d, d > 0 &
     x, ball x.1 d x.2 ball (f x.1) e (f x.2).
End entourages.

Lemma countable_uniformity_metric {R : realType} {T : pseudoMetricType R} :
  countable_uniformity T.

Specific pseudoMetric spaces

matrices
Section matrix_PseudoMetric.
Variables (m n : nat) (R : numDomainType) (T : pseudoMetricType R).
Implicit Types x y : 'M[T]_(m, n).
Definition mx_ball x (e : R) y := i j, ball (x i j) e (y i j).
Lemma mx_ball_center x (e : R) : 0 < e mx_ball x e x.
Lemma mx_ball_sym x y (e : R) : mx_ball x e y mx_ball y e x.
Lemma mx_ball_triangle x y z (e1 e2 : R) :
  mx_ball x e1 y mx_ball y e2 z mx_ball x (e1 + e2) z.

Lemma mx_entourage : entourage = entourage_ mx_ball.
Definition matrix_pseudoMetricType_mixin :=
  PseudoMetric.Mixin mx_ball_center mx_ball_sym mx_ball_triangle mx_entourage.
Canonical matrix_pseudoMetricType :=
  PseudoMetricType 'M[T]_(m, n) matrix_pseudoMetricType_mixin.
End matrix_PseudoMetric.

product of two pseudoMetric spaces
Section prod_PseudoMetric.
Context {R : numDomainType} {U V : pseudoMetricType R}.
Implicit Types (x y : U × V).
Definition prod_point : U × V := (point, point).
Definition prod_ball x (eps : R) y :=
  ball (fst x) eps (fst y) ball (snd x) eps (snd y).
Lemma prod_ball_center x (eps : R) : 0 < eps prod_ball x eps x.
Lemma prod_ball_sym x y (eps : R) : prod_ball x eps y prod_ball y eps x.
Lemma prod_ball_triangle x y z (e1 e2 : R) :
  prod_ball x e1 y prod_ball y e2 z prod_ball x (e1 + e2) z.
Lemma prod_entourage : entourage = entourage_ prod_ball.
Definition prod_pseudoMetricType_mixin :=
  PseudoMetric.Mixin prod_ball_center prod_ball_sym prod_ball_triangle prod_entourage.
End prod_PseudoMetric.
Canonical prod_pseudoMetricType (R : numDomainType) (U V : pseudoMetricType R) :=
  PseudoMetricType (U × V) (@prod_pseudoMetricType_mixin R U V).

Section Nbhs_fct2.
Context {T : Type} {R : numDomainType} {U V : pseudoMetricType R}.
Lemma fcvg_ball2P {F : set (set U)} {G : set (set V)}
  {FF : Filter F} {FG : Filter G} (y : U) (z : V):
  (F, G) --> (y, z)
   eps : R, eps > 0 \ y' \near F & z' \near G,
                ball y eps y' ball z eps z'.

Lemma cvg_ball2P {I J} {F : set (set I)} {G : set (set J)}
  {FF : Filter F} {FG : Filter G} (f : I U) (g : J V) (y : U) (z : V):
  (f @ F, g @ G) --> (y, z)
   eps : R, eps > 0 \ i \near F & j \near G,
                ball y eps (f i) ball z eps (g j).

End Nbhs_fct2.

Functional metric spaces
Section fct_PseudoMetric.
Variable (T : choiceType) (R : numFieldType) (U : pseudoMetricType R).
Definition fct_ball (x : T U) (eps : R) (y : T U) :=
   t : T, ball (x t) eps (y t).
Lemma fct_ball_center (x : T U) (e : R) : 0 < e fct_ball x e x.

Lemma fct_ball_sym (x y : T U) (e : R) : fct_ball x e y fct_ball y e x.
Lemma fct_ball_triangle (x y z : T U) (e1 e2 : R) :
  fct_ball x e1 y fct_ball y e2 z fct_ball x (e1 + e2) z.
Lemma fct_entourage : entourage = entourage_ fct_ball.
Definition fct_pseudoMetricType_mixin :=
  PseudoMetricMixin fct_ball_center fct_ball_sym fct_ball_triangle fct_entourage.
Canonical fct_pseudoMetricType := PseudoMetricType (T U) fct_pseudoMetricType_mixin.
End fct_PseudoMetric.

Definition quotient_topology (T : topologicalType) (Q : quotType T) := Q.

Section quotients.
Local Open Scope quotient_scope.
Context {T : topologicalType} {Q0 : quotType T}.

Let Q := quotient_topology Q0.

Canonical quotient_subtype := [subType Q of T by %/].
Canonical quotient_eq := EqType Q [eqMixin of Q by <:].
Canonical quotient_choice := ChoiceType Q [choiceMixin of Q by <:].
Canonical quotient_pointed := PointedType Q (\pi_Q point).

Definition quotient_open U := open (\pi_Q @^-1` U).

Program Definition quotient_topologicalType_mixin :=
  @topologyOfOpenMixin Q quotient_open _ _ _.

Let quotient_filtered := Filtered.Class (Pointed.class quotient_pointed)
  (nbhs_of_open quotient_open).

Canonical quotient_topologicalType := @Topological.Pack Q
  (@Topological.Class _ quotient_filtered quotient_topologicalType_mixin).

Let Q' := quotient_topologicalType.

Lemma pi_continuous : continuous (\pi_Q : T Q').

Lemma quotient_continuous {Z : topologicalType} (f : Q' Z) :
  continuous f continuous (f \o \pi_Q).

Lemma repr_comp_continuous (Z : topologicalType) (g : T Z) :
  continuous g {homo g : a b / a == b %[mod Q] >-> a == b}
  continuous (g \o repr : Q' Z).

End quotients.

Section discrete_pseudoMetric.
Context {R : numDomainType} {T : topologicalType} {dsc : discrete_space T}.

Definition discrete_ball (x : T) (eps : R) y : Prop := x = y.

Lemma discrete_ball_center x (eps : R) : 0 < eps discrete_ball x eps x.

Program Definition discrete_pseudoMetricType_mixin :=
  @PseudoMetric.Mixin R T discrete_ent discrete_ball _ _ _ _.

Definition discrete_pseudoMetricType := PseudoMetricType
  (@discrete_uniformType _ dsc) discrete_pseudoMetricType_mixin.

End discrete_pseudoMetric.

Definition pseudoMetric_bool {R : realType} :=
  @discrete_pseudoMetricType R [topologicalType of bool] discrete_bool.

Complete uniform spaces


Definition cauchy {T : uniformType} (F : set (set T)) := (F, F) --> entourage.

Lemma cvg_cauchy {T : uniformType} (F : set (set T)) : Filter F
  [cvg F in T] cauchy F.

Module Complete.
Definition axiom (T : uniformType) :=
   (F : set (set T)), ProperFilter F cauchy F F --> lim F.
Section ClassDef.
Record class_of (T : Type) := Class {
  base : Uniform.class_of T ;
  mixin : axiom (Uniform.Pack base)
}.
Structure type := Pack { sort; _ : class_of sort }.
Variables (T : Type) (cT : type).
Definition class := let: Pack _ c := cT return class_of cT in c.
Definition clone c of phant_id class c := @Pack T c.
Let xT := let: Pack T _ := cT in T.
Notation xclass := (class : class_of xT).
Definition pack b0 (m0 : axiom (@Uniform.Pack T b0)) :=
  fun bT b of phant_id (@Uniform.class bT) b
  fun m of phant_id m m0 ⇒ @Pack T (@Class T b m).
Definition eqType := @Equality.Pack cT xclass.
Definition choiceType := @Choice.Pack cT xclass.
Definition pointedType := @Pointed.Pack cT xclass.
Definition filteredType := @Filtered.Pack cT cT xclass.
Definition topologicalType := @Topological.Pack cT xclass.
Definition uniformType := @Uniform.Pack cT xclass.
End ClassDef.
Module Exports.
Coercion base : class_of >-> Uniform.class_of.
Coercion mixin : class_of >-> axiom.
Coercion sort : type >-> Sortclass.
Coercion eqType : type >-> Equality.type.
Canonical eqType.
Coercion choiceType : type >-> Choice.type.
Canonical choiceType.
Coercion pointedType : type >-> Pointed.type.
Canonical pointedType.
Coercion filteredType : type >-> Filtered.type.
Canonical filteredType.
Coercion topologicalType : type >-> Topological.type.
Canonical topologicalType.
Coercion uniformType : type >-> Uniform.type.
Canonical uniformType.
Notation completeType := type.
Notation "[ 'completeType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
  (at level 0, format "[ 'completeType' 'of' T 'for' cT ]") : form_scope.
Notation "[ 'completeType' 'of' T ]" := (@clone T _ _ id)
  (at level 0, format "[ 'completeType' 'of' T ]") : form_scope.
Notation CompleteType T m := (@pack T _ m _ _ idfun _ idfun).
End Exports.
End Complete.
Export Complete.Exports.

Section completeType1.

Context {T : completeType}.

Lemma cauchy_cvg (F : set (set T)) (FF : ProperFilter F) :
  cauchy F cvg F.

Lemma cauchy_cvgP (F : set (set T)) (FF : ProperFilter F) : cauchy F cvg F.

End completeType1.
Arguments cauchy_cvg {T} F {FF} _.
Arguments cauchy_cvgP {T} F {FF}.

Section matrix_Complete.

Variables (T : completeType) (m n : nat).

Lemma mx_complete (F : set (set 'M[T]_(m, n))) :
  ProperFilter F cauchy F cvg F.

Canonical matrix_completeType := CompleteType 'M[T]_(m, n) mx_complete.

End matrix_Complete.

Section fun_Complete.

Context {T : choiceType} {U : completeType}.

Lemma fun_complete (F : set (set (T U)))
  {FF : ProperFilter F} : cauchy F cvg F.

Canonical fun_completeType := CompleteType (T U) fun_complete.

End fun_Complete.

Limit switching

Section Cvg_switch.
Context {T1 T2 : choiceType}.

Lemma cvg_switch_1 {U : uniformType}
  F1 {FF1 : ProperFilter F1} F2 {FF2 : Filter F2}
  (f : T1 T2 U) (g : T2 U) (h : T1 U) (l : U) :
  f @ F1 --> g ( x1, f x1 @ F2 --> h x1) h @ F1 --> l
  g @ F2 --> l.

Lemma cvg_switch_2 {U : completeType}
  F1 {FF1 : ProperFilter F1} F2 {FF2 : ProperFilter F2}
  (f : T1 T2 U) (g : T2 U) (h : T1 U) :
  f @ F1 --> g ( x, f x @ F2 --> h x)
  [cvg h @ F1 in U].

Lemma cvg_switch {U : completeType}
  F1 (FF1 : ProperFilter F1) F2 (FF2 : ProperFilter F2)
  (f : T1 T2 U) (g : T2 U) (h : T1 U) :
  f @ F1 --> g ( x1, f x1 @ F2 --> h x1)
   l : U, h @ F1 --> l g @ F2 --> l.

End Cvg_switch.

Complete pseudoMetric spaces


Definition cauchy_ex {R : numDomainType} {T : pseudoMetricType R} (F : set (set T)) :=
   eps : R, 0 < eps x, F (ball x eps).

Definition cauchy_ball {R : numDomainType} {T : pseudoMetricType R} (F : set (set T)) :=
   e, e > 0 \ x & y \near F, ball x e y.

Lemma cauchy_ballP (R : numDomainType) (T : pseudoMetricType R)
    (F : set (set T)) (FF : Filter F) :
  cauchy_ball F cauchy F.
Arguments cauchy_ballP {R T} F {FF}.

Lemma cauchy_exP (R : numFieldType) (T : pseudoMetricType R)
    (F : set (set T)) (FF : Filter F) :
  cauchy_ex F cauchy F.
Arguments cauchy_exP {R T} F {FF}.

Lemma cauchyP (R : numFieldType) (T : pseudoMetricType R)
    (F : set (set T)) (PF : ProperFilter F) :
  cauchy F cauchy_ex F.
Arguments cauchyP {R T} F {PF}.

Lemma compact_cauchy_cvg {T : uniformType} (U : set T) (F : set (set T)) :
  ProperFilter F cauchy F F U compact U cvg F.

Module CompletePseudoMetric.
Section ClassDef.
Variable R : numDomainType.
Record class_of (T : Type) := Class {
  base : PseudoMetric.class_of R T;
  mixin : Complete.axiom (Uniform.Pack base)
}.
Definition base2 T m := Complete.Class (@mixin T m).

Structure type := Pack { sort; _ : class_of sort }.
Variables (T : Type) (cT : type).
Definition class := let: Pack _ c := cT return class_of cT in c.
Definition clone c of phant_id class c := @Pack T c.
Let xT := let: Pack T _ := cT in T.
Notation xclass := (class : class_of xT).
Definition pack :=
  fun bT b & phant_id (@PseudoMetric.class R bT) (b : PseudoMetric.class_of R T) ⇒
  fun mT m & phant_id (Complete.class mT) (@Complete.Class T b m) ⇒
  Pack (@Class T b m).
Definition eqType := @Equality.Pack cT xclass.
Definition choiceType := @Choice.Pack cT xclass.
Definition pointedType := @Pointed.Pack cT xclass.
Definition filteredType := @Filtered.Pack cT cT xclass.
Definition topologicalType := @Topological.Pack cT xclass.
Definition uniformType := @Uniform.Pack cT xclass.
Definition completeType := @Complete.Pack cT xclass.
Definition pseudoMetricType := @PseudoMetric.Pack R cT xclass.
Definition pseudoMetric_completeType := @Complete.Pack pseudoMetricType xclass.
End ClassDef.
Module Exports.
Coercion base : class_of >-> PseudoMetric.class_of.
Coercion mixin : class_of >-> Complete.axiom.
Coercion base2 : class_of >-> Complete.class_of.
Coercion sort : type >-> Sortclass.
Coercion eqType : type >-> Equality.type.
Canonical eqType.
Coercion choiceType : type >-> Choice.type.
Canonical choiceType.
Coercion pointedType : type >-> Pointed.type.
Canonical pointedType.
Coercion filteredType : type >-> Filtered.type.
Canonical filteredType.
Coercion topologicalType : type >-> Topological.type.
Canonical topologicalType.
Coercion uniformType : type >-> Uniform.type.
Canonical uniformType.
Coercion completeType : type >-> Complete.type.
Canonical completeType.
Coercion pseudoMetricType : type >-> PseudoMetric.type.
Canonical pseudoMetricType.
Canonical pseudoMetric_completeType.
Notation completePseudoMetricType := type.
Notation "[ 'completePseudoMetricType' 'of' T 'for' cT ]" := (@clone T cT _ idfun)
  (at level 0, format "[ 'completePseudoMetricType' 'of' T 'for' cT ]") : form_scope.
Notation "[ 'completePseudoMetricType' 'of' T ]" := (@clone T _ _ id)
  (at level 0, format "[ 'completePseudoMetricType' 'of' T ]") : form_scope.
Notation CompletePseudoMetricType T m := (@pack _ T _ _ id _ _ id).
End Exports.
End CompletePseudoMetric.
Export CompletePseudoMetric.Exports.

Canonical matrix_completePseudoMetricType (R : numFieldType)
  (T : completePseudoMetricType R) (m n : nat) :=
  CompletePseudoMetricType 'M[T]_(m, n) mx_complete.

Canonical fct_completePseudoMetricType (T : choiceType) (R : numFieldType)
  (U : completePseudoMetricType R) :=
  CompletePseudoMetricType (T U) fun_complete.

Definition pointed_of_zmodule (R : zmodType) : pointedType := PointedType R 0.

Definition ball_
  (R : numDomainType) (V : zmodType) (norm : V R) (x : V) (e : R) :=
  [set y | norm (x - y) < e].
Arguments ball_ {R} {V} norm x e%R y /.

Lemma subset_ball_prop_in_itv (R : realDomainType) (x : R) e P :
  (ball_ Num.Def.normr x e `<=` P)%classic
  {in `](x - e), (x + e)[, y, P y}.

Lemma subset_ball_prop_in_itvcc (R : realDomainType) (x : R) e P : 0 < e
  (ball_ Num.Def.normr x (2 × e) `<=` P)%classic
  {in `[(x - e), (x + e)], y, P y}.

Global Instance ball_filter (R : realFieldType) (t : R) : Filter
  [set P | exists2 i : R, 0 < i & ball_ Num.norm t i `<=` P].

Definition filtered_of_normedZmod (K : numDomainType) (R : normedZmodType K)
  : filteredType R := Filtered.Pack (Filtered.Class
    (@Pointed.class (pointed_of_zmodule R))
    (nbhs_ball_ (ball_ (fun x`|x|)))).

Section pseudoMetric_of_normedDomain.
Variables (K : numDomainType) (R : normedZmodType K).
Lemma ball_norm_center (x : R) (e : K) : 0 < e ball_ Num.norm x e x.
Lemma ball_norm_symmetric (x y : R) (e : K) :
  ball_ Num.norm x e y ball_ Num.norm y e x.
Lemma ball_norm_triangle (x y z : R) (e1 e2 : K) :
  ball_ Num.norm x e1 y ball_ Num.norm y e2 z ball_ Num.norm x (e1 + e2) z.
Definition pseudoMetric_of_normedDomain
  : PseudoMetric.mixin_of K (@entourage_ K R R (ball_ (fun x`|x|)))
  := PseudoMetricMixin ball_norm_center ball_norm_symmetric ball_norm_triangle erefl.
Lemma nbhs_ball_normE :
  @nbhs_ball_ K R R (ball_ Num.norm) = nbhs_ (entourage_ (ball_ Num.norm)).
End pseudoMetric_of_normedDomain.

Module regular_topology.

Section regular_topology.
End regular_topology.

Module Exports.
Canonical pointedType.
Canonical filteredType.
Canonical topologicalType.
Canonical uniformType.
Canonical pseudoMetricType.
End Exports.

End regular_topology.
Export regular_topology.Exports.

Module numFieldTopology.

Section realType.
Variable (R : realType).
End realType.

Section rcfType.
Variable (R : rcfType).
End rcfType.

Section archiFieldType.
Variable (R : archiFieldType).
End archiFieldType.

Section realFieldType.
Variable (R : realFieldType).
Definition pointed_latticeType := [latticeType of realField_pointedType].
Definition pointed_distrLatticeType :=
  [distrLatticeType of realField_pointedType].
Definition pointed_orderType := [orderType of realField_pointedType].
Definition pointed_realDomainType :=
  [realDomainType of realField_pointedType].
Definition filtered_latticeType := [latticeType of realField_filteredType].
Definition filtered_distrLatticeType :=
  [distrLatticeType of realField_filteredType].
Definition filtered_orderType := [orderType of realField_filteredType].
Definition filtered_realDomainType :=
  [realDomainType of realField_filteredType].
Definition topological_latticeType :=
  [latticeType of realField_topologicalType].
Definition topological_distrLatticeType :=
  [distrLatticeType of realField_topologicalType].
Definition topological_orderType := [orderType of realField_topologicalType].
Definition topological_realDomainType :=
  [realDomainType of realField_topologicalType].
Definition uniform_latticeType := [latticeType of realField_uniformType].
Definition uniform_distrLatticeType :=
  [distrLatticeType of realField_uniformType].
Definition uniform_orderType := [orderType of realField_uniformType].
Definition uniform_realDomainType := [realDomainType of realField_uniformType].
Definition pseudoMetric_latticeType :=
  [latticeType of realField_pseudoMetricType].
Definition pseudoMetric_distrLatticeType :=
  [distrLatticeType of realField_pseudoMetricType].
Definition pseudoMetric_orderType := [orderType of realField_pseudoMetricType].
Definition pseudoMetric_realDomainType :=
  [realDomainType of realField_pseudoMetricType].
End realFieldType.

Section numClosedFieldType.
Variable (R : numClosedFieldType).
Definition pointed_decFieldType :=
  [decFieldType of numClosedField_pointedType].
Definition pointed_closedFieldType :=
  [closedFieldType of numClosedField_pointedType].
Definition filtered_decFieldType :=
  [decFieldType of numClosedField_filteredType].
Definition filtered_closedFieldType :=
  [closedFieldType of numClosedField_filteredType].
Definition topological_decFieldType :=
  [decFieldType of numClosedField_topologicalType].
Definition topological_closedFieldType :=
  [closedFieldType of numClosedField_topologicalType].
Definition uniform_decFieldType := [decFieldType of numClosedField_uniformType].
Definition uniform_closedFieldType :=
  [closedFieldType of numClosedField_uniformType].
Definition pseudoMetric_decFieldType :=
  [decFieldType of numClosedField_pseudoMetricType].
Definition pseudoMetric_closedFieldType :=
  [closedFieldType of numClosedField_pseudoMetricType].
End numClosedFieldType.

Section numFieldType.
Variable (R : numFieldType).
Definition pointed_ringType := [ringType of numField_pointedType].
Definition pointed_comRingType := [comRingType of numField_pointedType].
Definition pointed_unitRingType := [unitRingType of numField_pointedType].
Definition pointed_comUnitRingType := [comUnitRingType of numField_pointedType].
Definition pointed_idomainType := [idomainType of numField_pointedType].
Definition pointed_fieldType := [fieldType of numField_pointedType].
Definition pointed_porderType := [porderType of numField_pointedType].
Definition pointed_numDomainType := [numDomainType of numField_pointedType].
Definition filtered_ringType := [ringType of numField_filteredType].
Definition filtered_comRingType := [comRingType of numField_filteredType].
Definition filtered_unitRingType := [unitRingType of numField_filteredType].
Definition filtered_comUnitRingType :=
  [comUnitRingType of numField_filteredType].
Definition filtered_idomainType := [idomainType of numField_filteredType].
Definition filtered_fieldType := [fieldType of numField_filteredType].
Definition filtered_porderType := [porderType of numField_filteredType].
Definition filtered_numDomainType := [numDomainType of numField_filteredType].
Definition topological_ringType := [ringType of numField_topologicalType].
Definition topological_comRingType := [comRingType of numField_topologicalType].
Definition topological_unitRingType :=
  [unitRingType of numField_topologicalType].
Definition topological_comUnitRingType :=
  [comUnitRingType of numField_topologicalType].
Definition topological_idomainType := [idomainType of numField_topologicalType].
Definition topological_fieldType := [fieldType of numField_topologicalType].
Definition topological_porderType := [porderType of numField_topologicalType].
Definition topological_numDomainType :=
  [numDomainType of numField_topologicalType].
Definition uniform_ringType := [ringType of numField_uniformType].
Definition uniform_comRingType := [comRingType of numField_uniformType].
Definition uniform_unitRingType := [unitRingType of numField_uniformType].
Definition uniform_comUnitRingType := [comUnitRingType of numField_uniformType].
Definition uniform_idomainType := [idomainType of numField_uniformType].
Definition uniform_fieldType := [fieldType of numField_uniformType].
Definition uniform_porderType := [porderType of numField_uniformType].
Definition uniform_numDomainType := [numDomainType of numField_uniformType].
Definition pseudoMetric_ringType := [ringType of numField_pseudoMetricType].
Definition pseudoMetric_comRingType :=
  [comRingType of numField_pseudoMetricType].
Definition pseudoMetric_unitRingType :=
  [unitRingType of numField_pseudoMetricType].
Definition pseudoMetric_comUnitRingType :=
  [comUnitRingType of numField_pseudoMetricType].
Definition pseudoMetric_idomainType :=
  [idomainType of numField_pseudoMetricType].
Definition pseudoMetric_fieldType := [fieldType of numField_pseudoMetricType].
Definition pseudoMetric_porderType := [porderType of numField_pseudoMetricType].
Definition pseudoMetric_numDomainType :=
  [numDomainType of numField_pseudoMetricType].
End numFieldType.

Module Exports.
realType
rcfType
archiFieldType
realFieldType
numClosedFieldType
numFieldType
Canonical numField_pointedType.
Canonical numField_filteredType.
Canonical numField_topologicalType.
Canonical numField_uniformType.
Canonical numField_pseudoMetricType.
Canonical pointed_ringType.
Canonical pointed_comRingType.
Canonical pointed_unitRingType.
Canonical pointed_comUnitRingType.
Canonical pointed_idomainType.
Canonical pointed_fieldType.
Canonical pointed_porderType.
Canonical pointed_numDomainType.
Canonical filtered_ringType.
Canonical filtered_comRingType.
Canonical filtered_unitRingType.
Canonical filtered_comUnitRingType.
Canonical filtered_idomainType.
Canonical filtered_fieldType.
Canonical filtered_porderType.
Canonical filtered_numDomainType.
Canonical topological_ringType.
Canonical topological_comRingType.
Canonical topological_unitRingType.
Canonical topological_comUnitRingType.
Canonical topological_idomainType.
Canonical topological_fieldType.
Canonical topological_porderType.
Canonical topological_numDomainType.
Canonical uniform_ringType.
Canonical uniform_comRingType.
Canonical uniform_unitRingType.
Canonical uniform_comUnitRingType.
Canonical uniform_idomainType.
Canonical uniform_fieldType.
Canonical uniform_porderType.
Canonical uniform_numDomainType.
Canonical pseudoMetric_ringType.
Canonical pseudoMetric_comRingType.
Canonical pseudoMetric_unitRingType.
Canonical pseudoMetric_comUnitRingType.
Canonical pseudoMetric_idomainType.
Canonical pseudoMetric_fieldType.
Canonical pseudoMetric_porderType.
Canonical pseudoMetric_numDomainType.
Coercion numField_pointedType : numFieldType >-> pointedType.
Coercion numField_filteredType : numFieldType >-> filteredType.
Coercion numField_topologicalType : numFieldType >-> topologicalType.
Coercion numField_uniformType : numFieldType >-> uniformType.
Coercion numField_pseudoMetricType : numFieldType >-> pseudoMetricType.
End Exports.

End numFieldTopology.
Import numFieldTopology.Exports.

Global Instance Proper_dnbhs_regular_numFieldType (R : numFieldType) (x : R^o) :
  ProperFilter x^'.

Lemma Rhausdorff (R : realFieldType) : hausdorff_space R.

Section RestrictedUniformTopology.
Context {U : choiceType} (A : set U) {V : uniformType} .

Definition fct_RestrictedUniform := let _ := A in U V.
Definition fct_RestrictedUniformTopology :=
  @weak_uniformType
    ([pointedType of @fct_RestrictedUniform])
    (fct_uniformType [choiceType of { x : U | x \in A }] V)
    (@sigL U V A).

Canonical fct_RestrictUniformFilteredType:=
  [filteredType fct_RestrictedUniform of
      fct_RestrictedUniform for
      fct_RestrictedUniformTopology].

Canonical fct_RestrictUniformTopologicalType :=
  [topologicalType of fct_RestrictedUniform for fct_RestrictedUniformTopology].

Canonical fct_restrictedUniformType :=
  [uniformType of fct_RestrictedUniform for fct_RestrictedUniformTopology].

Lemma uniform_nbhs (f : fct_RestrictedUniformTopology) P:
  nbhs f P ( E, entourage E
    [set h | y, A y E(f y, h y)] `<=` P).

Lemma uniform_entourage :
  @entourage fct_restrictedUniformType =
  filter_from
    (@entourage V)
    (fun P[set fg | t : U, A t P (fg.1 t, fg.2 t)]).

End RestrictedUniformTopology.

Notation "{ 'uniform`' A -> V }" := (@fct_RestrictedUniform _ A V) :
  classical_set_scope.
Notation "{ 'uniform' U -> V }" := ({uniform` [set: U] V}) :
  classical_set_scope.

Notation "{ 'uniform' A , F --> f }" :=
  (cvg_to [filter of F]
     (filter_of (Phantom (fct_RestrictedUniform A) f)))
   : classical_set_scope.
Notation "{ 'uniform' , F --> f }" :=
  (cvg_to [filter of F]
     (filter_of (Phantom (fct_RestrictedUniform setT) f)))
   : classical_set_scope.

We use this function to help coq identify the correct notation to use when printing. Otherwise you get goals like `F --> f -> F --> f`

Lemma restricted_cvgE {U : choiceType} {V : uniformType}
    (F : set (set (U V))) A (f : U V) :
  {uniform A, F --> f} = (F --> (f : {uniform` A V})).

Definition fct_Pointwise U (V: topologicalType) := U V.

Definition fct_PointwiseTopology (U : Type) (V : topologicalType) :=
  @product_topologicalType U (fun V).

Canonical fct_PointwiseFilteredType (U : Type) (V : topologicalType) :=
  [filteredType @fct_Pointwise U V of
     @fct_Pointwise U V for
     @fct_PointwiseTopology U V].

Canonical fct_PointwiseTopologicalType (U : Type) (V : topologicalType) :=
  [topologicalType of
     @fct_Pointwise U V for
     @fct_PointwiseTopology U V].

Notation "{ 'ptws' U -> V }" := (@fct_Pointwise U V).

Notation "{ 'ptws' , F --> f }" :=
  (cvg_to [filter of F] (filter_of (Phantom (@fct_Pointwise _ _) f)))
  : classical_set_scope.

Lemma pointwise_cvgE {U : Type} {V : topologicalType}
    (F : set (set(U V))) (A : set U) (f : U V) :
  {ptws, F --> f} = (F --> (f : {ptws U V})).

Section UniformCvgLemmas.
Context {U : choiceType} {V : uniformType}.

Lemma uniform_set1 F (f : U V) (x : U) :
  Filter F {uniform [set x], F --> f} = ((g x) @[g --> F] --> f x).

Lemma uniform_subset_nbhs (f : U V) (A B : set U) :
  B `<=` A nbhs (f : {uniform` A V}) `=>` nbhs (f : {uniform` B V}).

Lemma uniform_subset_cvg (f : U V) (A B : set U) F :
  Filter F B `<=` A {uniform A, F --> f} {uniform B, F --> f}.

Lemma pointwise_uniform_cvg (f : U V) (F : set (set (U V))) :
  Filter F {uniform, F --> f} {ptws, F --> f}.

Lemma cvg_sigL (A : set U) (f : U V) (F : set (set (U V))) :
    Filter F
  {uniform A, F --> f}
  {uniform, sigL A @ F --> sigL A f}.

Lemma eq_in_close (A : set U) (f g : {uniform` A V}) :
  {in A, f =1 g} close f g.

Lemma hausdorrf_close_eq_in (A : set U) (f g : {uniform` A V}) :
  hausdorff_space V close f g = {in A, f =1 g}.

Lemma uniform_restrict_cvg
    (F : set (set (U V))) (f : U V) A : Filter F
  {uniform A, F --> f} {uniform, restrict A @ F --> restrict A f}.

Lemma uniform_nbhsT (f : U V) :
  (nbhs (f : {uniform U V})) = nbhs (f : fct_topologicalType U V).

Lemma cvg_uniformU (f : U V) (F : set (set (U V))) A B : Filter F
  {uniform A, F --> f} {uniform B, F --> f}
  {uniform (A `|` B), F --> f}.

Lemma cvg_uniform_set0 (F : set (set (U V))) (f : U V) : Filter F
  {uniform set0, F --> f}.

Definition fct_UniformFamily (fam : (set U) Prop) := U V.

Definition family_cvg_uniformType (fam: set U Prop) :=
  @sup_uniformType _
    (sigT fam)
    (fun kUniform.class (@fct_restrictedUniformType U (projT1 k) V)).

Canonical fct_UniformFamilyFilteredType fam :=
  [filteredType fct_UniformFamily fam of
    fct_UniformFamily fam for
    family_cvg_uniformType fam].

Canonical fct_UniformFamilyTopologicalType fam :=
  [topologicalType of
     fct_UniformFamily fam for
     family_cvg_uniformType fam].

Canonical fct_UniformFamilyUniformType fam :=
  [uniformType of
     fct_UniformFamily fam for
     family_cvg_uniformType fam].


Lemma fam_cvgP (fam : set U Prop) (F : set (set (U V))) (f : U V) :
  Filter F {family fam, F --> f}
  ( A : set U, fam A {uniform A, F --> f }).

Lemma family_cvg_subset (famA famB : set U Prop) (F : set (set (U V)))
    (f : U V) : Filter F
  famA `<=` famB {family famB, F --> f} {family famA, F --> f}.

Lemma family_cvg_finite_covers (famA famB : set U Prop)
  (F : set (set (U V))) (f : U V) : Filter F
  ( P, famA P
     (I : choiceType) f,
      ( i, famB (f i)) finite_subset_cover [set: I] f P)
  {family famB, F --> f} {family famA, F --> f}.

End UniformCvgLemmas.

Notation "{ 'family' fam , U -> V }" := (@fct_UniformFamily U V fam).
Notation "{ 'family' fam , F --> f }" :=
  (cvg_to [filter of F] (filter_of (Phantom (fct_UniformFamily fam) f)))
  : classical_set_scope.

Lemma fam_cvgE {U : choiceType} {V : uniformType} (F : set (set (U V)))
    (f : U V) fam :
  {family fam, F --> f} = (F --> (f : {family fam, U V})).

Lemma fam_nbhs {U : choiceType} {V : uniformType} (fam : set U Prop)
    (A : set U) (E : set (V × V)) (f : {family fam, U V}) :
  entourage E fam A nbhs f [set g | y, A y E (f y, g y)].

Definition compactly_in {U : topologicalType} (A : set U) :=
  [set B | B `<=` A compact B].

Lemma compact_cvg_within_compact {U : topologicalType} {V : uniformType}
    (C : set U) (F : set (set (U V))) (f : U V) :
  Filter F compact C
  {uniform C, F --> f} {family compactly_in C, F --> f}.

Global Instance Proper_dnbhs_numFieldType (R : numFieldType) (x : R) :
  ProperFilter x^'.

Definition dense (T : topologicalType) (S : set T) :=
   (O : set T), O !=set0 open O O `&` S !=set0.

Lemma denseNE (T : topologicalType) (S : set T) : ¬ dense S
   O, ( x, open_nbhs x O) (O `&` S = set0).

Lemma dense_rat (R : realType) : dense (@ratr R @` setT).

Section weak_pseudoMetric.
Context {R : realType} (pS : pointedType) (U : pseudoMetricType R) .
Variable (f : pS U).

Let S := weak_uniformType f.

Definition weak_ball (x : S) (r : R) (y : S) := ball (f x) r (f y).

Program Definition weak_pseudoMetricType_mixin :=
  @PseudoMetric.Mixin R S entourage weak_ball
  _ _ _ _.


Definition weak_pseudoMetricType :=
  PseudoMetricType S weak_pseudoMetricType_mixin.

Lemma weak_ballE (e : R) (x : weak_pseudoMetricType) :
  f@^-1` (ball (f x) e) = ball x e.

End weak_pseudoMetric.

Lemma compact_second_countable {R : realType} {T : pseudoMetricType R} :
  compact [set: T] @second_countable T.

This section proves that uniform spaces, with a countable base for their entourage, are metrizable. The definition of this metric is rather arcane, and the proof is tough. That's ok because the resulting metric is not intended to be used explicitly. Instead, this is typically used in applications that do not depend on the metric:
  • `metric spaces are T4`
  • `in metric spaces, compactness and sequential compactness agree`
  • infinite products of metric spaces are metrizable
Section countable_uniform.
Context {R : realType} {T : uniformType}.

Hypothesis cnt_unif : @countable_uniformity T.

Let f_ := projT1 (cid2 (iffLR countable_uniformityP cnt_unif)).


Let entF : n, entourage (f_ n).

Step 1: We build a nicer base `g` for `entourage` with better assumptions than `f`
  • each (g_ n) is symmetric
  • the sets (g_ n) are nested downward
  • g_ n.+1 \o g_ n.+1 \o g_ n.+1 `<=` g_ n says the sets descend `quickly`


Let entG (n : nat) : entourage (g_ n).







Step 2. We build a sensible notion of balls for our metric. The naive attempt, `ball x e y := g_ (distN e) (x,y)) doesn't respect triangle inequality. We need to cook triangle inequality into the balls themselves. So we define balls in terms of steps: `ball x e y := there are n steps x_0 = x,...,x_i,..., x_n.+1 = y and e_1,...,e_n such that g_ (distN e_i) (x_i,x_i+1) and sum (e_i) = e

Local Open Scope classical_set_scope.
Local Open Scope ring_scope.
















Step 3: We prove that step_ball respects the original entourage. This requires an induction on the length of the steps, which is pretty tricky. The central lemma is `split_n_step_ball`, which lets us break a list into parts three parts as: half + one_step + half. Then our we can break apart our n +1 path nlong + one_step into (half + one_step + half) + one_step = half + one_step + (half + one_step) and we can we can use our (strong) induction hypothesis. And lastly we finish with splitG3.









Note these are the only non-local result from this section
Definition countable_uniform_pseudoMetricType_mixin := PseudoMetric.Mixin
  step_ball_center step_ball_sym step_ball_triangle step_ball_entourage.

Lemma countable_uniform_bounded (x y : T) :
  let U := PseudoMetricType _ countable_uniform_pseudoMetricType_mixin
  in @ball _ U x 2 y.

End countable_uniform.

Section sup_pseudometric.
Variable (R : realType) (T : pointedType) (Ii : Type).
Variable (Tc : Ii PseudoMetric.class_of R T).

Hypothesis Icnt : countable [set: Ii].

Let I : choiceType := classicType_choiceType Ii.
Let TS := fun iPseudoMetric.Pack (Tc i).

Definition countable_uniformityT := @countable_sup_ent T Ii Tc Icnt
  (fun i ⇒ @countable_uniformity_metric _ (TS i)).

Definition sup_pseudoMetric_mixin := @countable_uniform_pseudoMetricType_mixin R
  (sup_uniformType Tc) countable_uniformityT.

Definition sup_pseudoMetricType :=
  PseudoMetricType (sup_uniformType Tc) sup_pseudoMetric_mixin.

End sup_pseudometric.

Section product_pseudometric.
Variable (R : realType) (Ii : countType) (Tc : Ii pseudoMetricType R).

Hypothesis Icnt : countable [set: Ii].

Definition product_pseudoMetricType :=
  sup_pseudoMetricType (fun iPseudoMetric.class
    (weak_pseudoMetricType (fun f : dep_arrow_pointedType Tcf i)))
    Icnt.

End product_pseudometric.

Definition subspace {T : Type} (A : set T) := T.
Arguments subspace {T} _ : simpl never.

Definition incl_subspace {T A} (x : subspace A) : T := x.

Section Subspace.
Context {T : topologicalType} (A : set T).

Definition nbhs_subspace (x : subspace A) : set (set (subspace A)) :=
  if x \in A then within A (nbhs x) else globally [set x].

Variant nbhs_subspace_spec x : Prop Prop bool set (set T) Type :=
  | WithinSubspace :
      A x nbhs_subspace_spec x True False true (within A (nbhs x))
  | WithoutSubspace :
    ¬ A x nbhs_subspace_spec x False True false (globally [set x]).

Lemma nbhs_subspaceP x :
  nbhs_subspace_spec x (A x) (¬ A x) (x \in A) (nbhs_subspace x).

Lemma nbhs_subspace_in (x : T) : A x within A (nbhs x) = nbhs_subspace x.

Lemma nbhs_subspace_out (x : T) : ¬ A x globally [set x] = nbhs_subspace x.

Lemma nbhs_subspace_filter (x : subspace A) : ProperFilter (nbhs_subspace x).

Definition subspace_pointedType := PointedType (subspace A) point.

Canonical subspace_filteredType :=
  FilteredType (subspace A) (subspace A) nbhs_subspace.

Program Definition subspace_topologicalMixin :
  Topological.mixin_of (nbhs_subspace) := @topologyOfFilterMixin
    (subspace A) nbhs_subspace nbhs_subspace_filter _ _.

Canonical subspace_topologicalType :=
  TopologicalType (subspace A) subspace_topologicalMixin.

Lemma subspace_cvgP (F : set (set T)) (x : T) :
  Filter F A x
  (F --> (x : subspace A)) (F --> within A (nbhs x)).

Lemma subspace_continuousP {S : topologicalType} (f : T S) :
  continuous (f : subspace A S)
  ( x, A x f @ within A (nbhs x) --> f x) .

Lemma subspace_eq_continuous {S : topologicalType} (f g : subspace A S) :
  {in A, f =1 g} continuous f continuous g.

Lemma continuous_subspace_in {U : topologicalType} (f : subspace A U) :
  continuous f = {in A, continuous f}.

Lemma nbhs_subspace_interior (x : T) :
  A x nbhs x = (nbhs (x : subspace A)).

Lemma nbhs_subspace_ex (U : set T) (x : T) : A x
  nbhs (x : subspace A) U
  exists2 V, nbhs (x : T) V & U `&` A = V `&` A.

Lemma incl_subspace_continuous : continuous incl_subspace.

Section SubspaceOpen.

Lemma open_subspace1out (x : subspace A) : ¬ A x open [set x].

Lemma open_subspace_out (U : set (subspace A)) : U `<=` ~` A open U.

Lemma open_subspaceT : open (A : set (subspace A)).

Lemma open_subspaceIT (U : set (subspace A)) : open (U `&` A) = open U.

Lemma open_subspaceTI (U : set (subspace A)) :
  open (A `&` U : set (subspace A)) = open U.

Lemma closed_subspaceT : closed (A : set (subspace A)).

Lemma open_subspaceP (U : set T) :
  open (U : set (subspace A))
   V, open (V : set T) V `&` A = U `&` A.

Lemma closed_subspaceP (U : set T) :
  closed (U : set (subspace A))
   V, closed (V : set T) V `&` A = U `&` A.

Lemma open_subspaceW (U : set T) :
  open (U : set T) open (U : set (subspace A)).

Lemma closed_subspaceW (U : set T) :
  closed (U : set T) closed (U : set (subspace A)).

Lemma open_setIS (U : set (subspace A)) : open A
  open (U `&` A : set T) = open U.

Lemma open_setSI (U : set (subspace A)) : open A open (A `&` U) = open U.

Lemma closed_setIS (U : set (subspace A)) : closed A
  closed (U `&` A : set T) = closed U.

Lemma closed_setSI (U : set (subspace A)) :
  closed A closed (A `&` U) = closed U.

Lemma closure_subspaceW (U : set T) :
  U `<=` A closure (U : set (subspace A)) = closure (U : set T) `&` A.

Lemma subspace_hausdorff :
  hausdorff_space T hausdorff_space [topologicalType of subspace A].
End SubspaceOpen.

Lemma compact_subspaceIP (U : set T) :
  compact (U `&` A : set (subspace A)) compact (U `&` A : set T).

Lemma clopen_connectedP : connected A
  ( U, @clopen (subspace_topologicalType) U
    U `<=` A U !=set0 U = A).

End Subspace.

Global Instance subspace_filter {T : topologicalType}
     (A : set T) (x : subspace A) :
   Filter (nbhs_subspace x) := nbhs_subspace_filter x.

Global Instance subspace_proper_filter {T : topologicalType}
     (A : set T) (x : subspace A) :
   ProperFilter (nbhs_subspace x) := nbhs_subspace_filter x.

Notation "{ 'within' A , 'continuous' f }" := (continuous (f : subspace A -> _)).
Notation "{ 'within' A , 'continuous' f }" := ( x,
  cvg_to [filter of fmap f (filter_of (Phantom (subspace A) x))]
         [filter of f x]) : classical_set_scope.

Section SubspaceRelative.
Context {T : topologicalType}.
Implicit Types (U : topologicalType) (A B : set T).

Lemma nbhs_subspace_subset A B (x : T) :
  A `<=` B nbhs (x : subspace B) `<=` nbhs (x : subspace A).

Lemma continuous_subspaceW {U} A B (f : T U) :
  A `<=` B
  {within B, continuous f} {within A, continuous f}.

Lemma nbhs_subspaceT (x : T) : nbhs (x : subspace setT) = nbhs x.

Lemma continuous_subspaceT_for {U} A (f : T U) (x : T) :
  A x {for x, continuous f} {for x, continuous (f : subspace A U)}.

Lemma continuous_in_subspaceT {U} A (f : T U) :
  {in A, continuous f} {within A, continuous f}.

Lemma continuous_subspaceT {U} A (f : T U) :
  continuous f {within A, continuous f}.

Lemma continuous_open_subspace {U} A (f : T U) :
  open A {within A, continuous f} = {in A, continuous f}.

Lemma continuous_inP {U} A (f : T U) : open A
  {in A, continuous f} X, open X open (A `&` f @^-1` X).

pasting lemma
Lemma withinU_continuous {U} A B (f : T U) : closed A closed B
  {within A, continuous f} {within B, continuous f}
  {within A `|` B, continuous f}.

Lemma subspaceT_continuous {U} A (B : set U) (f : {fun A >-> B}) :
  {within A, continuous f} continuous (f : subspace A subspace B).

Lemma continuous_subspace0 {U} (f : T U) : {within set0, continuous f}.

Lemma continuous_subspace1 {U} (a : T) (f : T U) :
  {within [set a], continuous f}.

End SubspaceRelative.

Section SubspaceUniform.
Context {X : uniformType} (A : set X).

Definition subspace_ent :=
  filter_from (@entourage X)
  (fun E[set xy | (xy.1 = xy.2) (A xy.1 A xy.2 E xy)]).

Program Definition subspace_uniformMixin :=
  @Uniform.Mixin (subspace A) (@nbhs_subspace _ _) subspace_ent _ _ _ _ _.

Canonical subspace_uniformType :=
  UniformType (subspace A) subspace_uniformMixin.
End SubspaceUniform.

Section SubspacePseudoMetric.
Context {R : numDomainType} {X : pseudoMetricType R} (A : set X).

Definition subspace_ball (x : subspace A) (r : R) :=
  if x \in A then A `&` ball (x : X) r else [set x].

Program Definition subspace_pseudoMetricType_mixin :=
  @PseudoMetric.Mixin R (subspace A) (subspace_ent A) (subspace_ball)
  _ _ _ _.

Canonical subspace_pseudoMetricType :=
  PseudoMetricType (subspace A) subspace_pseudoMetricType_mixin.

End SubspacePseudoMetric.

Section SubspaceWeak.
Context {T : topologicalType} {U : pointedType}.
Variables (f : U T).

Let U' := weak_topologicalType f.

Lemma weak_subspace_open (A : set U') :
  open A open (f @` A : set (subspace (range f))).

End SubspaceWeak.

Definition separate_points_from_closed {I : Type} {T : topologicalType}
    {U_ : I topologicalType} (f_ : i, T U_ i) :=
   (U : set T) x,
  closed U ¬ U x i, ¬ (closure (f_ i @` U)) (f_ i x).

A handy technique for embedding a space T into a product. The key interface is 'separate_points_from_closed', which guarantees that the topologies
  • T's native topology
  • sup (weak f_i) - the sup of all the weak topologies of f_i
  • weak (x => (f_1 x, f_2 x,...)) - the weak topology from the product space
are equivalent (the last equivalence seems to require accessible_space).
Section product_embeddings.
Context {I : choiceType} {T : topologicalType} {U_ : I topologicalType}.
Variable (f_ : i, T U_ i).

Hypothesis sepf : separate_points_from_closed f_.
Hypothesis ctsf : i, continuous (f_ i).

Let weakT := @sup_topologicalType T I
  (fun iTopological.class (weak_topologicalType (f_ i))).

Let PU := product_topologicalType U_.


Lemma weak_sep_cvg (F : set (set T)) (x : T) :
  Filter F (F --> (x : T)) (F --> (x : weakT)).

Lemma weak_sep_nbhsE x : @nbhs T T x = @nbhs T weakT x.

Lemma weak_sep_openE : @open T = @open weakT.

Definition join_product (x : T) : PU := f_ ^~ x.

Lemma join_product_continuous : continuous join_product.


Lemma join_product_open (A : set T) : open A
  open ((join_product @` A) : set (subspace (range join_product))).

Lemma join_product_inj : accessible_space T set_inj [set: T] join_product.

Lemma join_product_weak : set_inj [set: T] join_product
  @open T = @open (weak_topologicalType join_product).

End product_embeddings.

Lemma continuous_compact {T U : topologicalType} (f : T U) A :
  {within A, continuous f} compact A compact (f @` A).

Lemma connected_continuous_connected (T U : topologicalType)
    (A : set T) (f : T U) :
  connected A {within A, continuous f} connected (f @` A).

Lemma uniform_limit_continuous {U : topologicalType} {V : uniformType}
    (F : set (set (U V))) (f : U V) :
  ProperFilter F (\ g \near F, continuous (g : U V))
  {uniform, F --> f} continuous f.

Lemma uniform_limit_continuous_subspace {U : topologicalType} {V : uniformType}
    (K : set U) (F : set (set (U V))) (f : subspace K V) :
  ProperFilter F (\ g \near F, continuous (g : subspace K V))
  {uniform K, F --> f} {within K, continuous f}.

Lemma continuous_localP {X Y : topologicalType} (f : X Y) :
  continuous f
   (x : X), \ U \near powerset_filter_from (nbhs x),
    {within U, continuous f}.

Lemma totally_disconnected_prod (I : choiceType)
  (T : I topologicalType) (A : i, set (T i)) :
  ( i, totally_disconnected (A i))
  @totally_disconnected (product_topologicalType T)
    (fun f i, A i (f i)).

Section UniformPointwise.
Context {U : topologicalType} {V : uniformType}.

Definition singletons {T : Type} := [set [set x] | x in [set: T]].

Lemma pointwise_cvg_family_singleton F (f: U V):
  Filter F {ptws, F --> f} = {family @singletons U, F --> f}.

Lemma pointwise_cvg_compact_family F (f : U V) :
  Filter F {family compact, F --> f} {ptws, F --> f}.

Lemma pointwise_cvgP F (f: U V):
  Filter F {ptws, F --> f} (t : U), (fun gg t) @ F --> f t.

End UniformPointwise.

Section gauges.

Let split_sym {T : uniformType} (W : set (T × T)) :=
  (split_ent W) `&` (split_ent W)^-1.

Section entourage_gauge.
Context {T : uniformType} (E : set (T × T)) (entE : entourage E).

Definition gauge :=
  filter_from [set: nat] (fun niter n split_sym (E `&` E^-1)).

Lemma iter_split_ent j : entourage (iter j split_sym (E `&` E^-1)).

Lemma gauge_ent A : gauge A entourage A.

Lemma gauge_filter : Filter gauge.

Lemma gauge_refl A : gauge A [set fg | fg.1 = fg.2] `<=` A.

Lemma gauge_inv A : gauge A gauge (A^-1)%classic.

Lemma gauge_split A : gauge A exists2 B, gauge B & B \; B `<=` A.

Definition gauge_uniformType_mixin :=
 UniformMixin gauge_filter gauge_refl gauge_inv gauge_split erefl.

Definition gauge_topologicalTypeMixin :=
  topologyOfEntourageMixin gauge_uniformType_mixin.

Definition gauge_filtered := FilteredType T T (nbhs_ gauge).
Definition gauge_topologicalType :=
  TopologicalType gauge_filtered gauge_topologicalTypeMixin.
Definition gauge_uniformType := UniformType
  gauge_topologicalType gauge_uniformType_mixin.

Lemma gauge_countable_uniformity : countable_uniformity gauge_uniformType.

Definition gauge_pseudoMetric_mixin {R : realType} :=
  @countable_uniform_pseudoMetricType_mixin R _ gauge_countable_uniformity.

Definition gauge_pseudoMetricType {R : realType} :=
  PseudoMetricType gauge_uniformType (@gauge_pseudoMetric_mixin R).

End entourage_gauge.

Lemma uniform_pseudometric_sup {R : realType} {T : uniformType} :
    @entourage T = @sup_ent T {E : set (T × T) | @entourage T E}
  (fun EUniform.class (@gauge_pseudoMetricType T (projT1 E) (projT2 E) R)).

End gauges.

Definition normal_space (T : topologicalType) :=
   A : set T, closed A
    set_nbhs A `<=` filter_from (set_nbhs A) closure.

Definition regular_space (T : topologicalType) :=
   a : T, nbhs a `<=` filter_from (nbhs a) closure.

Section ArzelaAscoli.
Context {X : topologicalType}.
Context {Y : uniformType}.
Context {hsdf : hausdorff_space Y}.
Implicit Types (I : Type).

The key condition in Arzela-Ascoli that, like uniform continuity, moves a quantifier around so all functions have the same 'deltas'.
A convenient notion that is in between compactness in {family compact, X -> y} and compactness in {ptws X -> y}.
Definition pointwise_precompact {I} (W : set I) (d : I X Y) :=
   x, precompact [set (d i x) | i in W].

Lemma pointwise_precompact_subset {I J} (W : set I) (V : set J)
    {fW : I X Y} {fV : J X Y} :
  fW @` W `<=` fV @` V pointwise_precompact V fV
  pointwise_precompact W fW.

Lemma pointwise_precompact_precompact {I} (W : set I) (fW : I (X Y)) :
  pointwise_precompact W fW precompact ((fW @` W) : set {ptws X Y}).

Lemma uniform_pointwise_compact (W : set (X Y)) :
  compact (W : set (@fct_UniformFamily X Y compact))
  compact (W : set {ptws X Y}).

Lemma precompact_pointwise_precompact (W : set {family compact, X Y}) :
  precompact W pointwise_precompact W id.

Lemma pointwise_cvg_entourage (x : X) (f : {ptws X Y}) E :
  entourage E \ g \near f, E (f x, g x).

Lemma equicontinuous_closure (W : set {ptws X Y}) :
  equicontinuous W id equicontinuous (closure W) id.

Definition small_ent_sub := @small_set_sub _ _ (@entourage Y).

Lemma pointwise_compact_cvg (F : set (set {ptws X Y})) (f : {ptws X Y}) :
  ProperFilter F
  (\ W \near powerset_filter_from F, equicontinuous W id)
  {ptws, F --> f} {family compact, F --> f}.

Lemma pointwise_compact_closure (W : set (X Y)) :
  equicontinuous W id
  closure (W : set {family compact, X Y}) =
  closure (W : set {ptws X Y}).

Lemma pointwise_precompact_equicontinuous (W : set (X Y)) :
  pointwise_precompact W id
  equicontinuous W id
  precompact (W : set {family compact, X Y }).

Section precompact_equicontinuous.
Hypothesis lcptX : locally_compact [set: X].

Let compact_equicontinuous (W : set {family compact, X Y}) :
  ( f, W f continuous f)
  compact (W : set {family compact, X Y})
  equicontinuous W id.

Lemma precompact_equicontinuous (W : set {family compact, X Y}) :
  ( f, W f continuous f)
  precompact (W : set {family compact, X Y})
  equicontinuous W id.

End precompact_equicontinuous.

Theorem Ascoli (W : set {family compact, X Y}) :
    locally_compact [set: X]
  pointwise_precompact W id equicontinuous W id
    ( f, W f continuous f)
    precompact (W : set {family compact, X Y}).

End ArzelaAscoli.