(*              (c) Copyright, John Harrison 1998-2014                       *)
(*              (c) Copyright, Valentina Bruno 2010                          *)
(*          Distributed under the same license as HOL Light                  *)
(*                                                                           *)
(* Theorems taken directly from Multivariate/topology.ml which run after     *)
(* loading Topology.ml.                                                      *)
needs "Library/card.ml";;
needs "Multivariate/determinants.ml";;
needs "RichterHilbertAxiomGeometry/Topology.ml";;
(* ------------------------------------------------------------------------- *)
(* Open and closed balls and spheres.                                        *)
(* ------------------------------------------------------------------------- *)
add_translation_invariants
  [BALL_TRANSLATION; CBALL_TRANSLATION; SPHERE_TRANSLATION];;
let BALL_LINEAR_IMAGE = prove
 (`!f:real^M->real^N x r.
        linear f /\ (!y. ?x. f x = y) /\ (!x. norm(f x) = norm x)
        ==> ball(f x,r) = 
IMAGE f (ball(x,r))`,
  REWRITE_TAC[ball] THEN GEOM_TRANSFORM_TAC[]);;
 
 
let CBALL_LINEAR_IMAGE = prove
 (`!f:real^M->real^N x r.
        linear f /\ (!y. ?x. f x = y) /\ (!x. norm(f x) = norm x)
        ==> cball(f x,r) = 
IMAGE f (cball(x,r))`,
  REWRITE_TAC[cball] THEN GEOM_TRANSFORM_TAC[]);;
 
 
let SPHERE_LINEAR_IMAGE = prove
 (`!f:real^M->real^N x r.
        linear f /\ (!y. ?x. f x = y) /\ (!x. norm(f x) = norm x)
        ==> sphere(f x,r) = 
IMAGE f (sphere(x,r))`,
  REWRITE_TAC[sphere] THEN GEOM_TRANSFORM_TAC[]);;
 
 
add_linear_invariants
  [BALL_LINEAR_IMAGE; CBALL_LINEAR_IMAGE; SPHERE_LINEAR_IMAGE];;
add_scaling_theorems [BALL_SCALING; CBALL_SCALING];;
(* ------------------------------------------------------------------------- *)
(* Also some invariance theorems for relative topology.                      *)
(* ------------------------------------------------------------------------- *)
add_translation_invariants [OPEN_IN_TRANSLATION_EQ];;
add_translation_invariants [CLOSED_IN_TRANSLATION_EQ];;
(* ------------------------------------------------------------------------- *)
(* Limit points.                                                             *)
(* ------------------------------------------------------------------------- *)
let CLOSED_POSITIVE_ORTHANT = prove
 (`closed {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
                          ==> &0 <= x$i}`,
  REWRITE_TAC[
CLOSED_LIMPT; 
LIMPT_APPROACHABLE] THEN
  REWRITE_TAC[
IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
  X_GEN_TAC `i:num` THEN STRIP_TAC THEN REWRITE_TAC[GSYM 
REAL_NOT_LT] THEN
  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `--(x:real^N $ i)`) THEN
  ASM_REWRITE_TAC[
REAL_LT_RNEG; REAL_ADD_LID; 
NOT_EXISTS_THM] THEN
  X_GEN_TAC `y:real^N` THEN
  MATCH_MP_TAC(TAUT `(a ==> ~c) ==> ~(a /\ b /\ c)`) THEN DISCH_TAC THEN
  MATCH_MP_TAC(REAL_ARITH `!b. abs x <= b /\ b <= a ==> ~(a + x < &0)`) THEN
  EXISTS_TAC `abs((y - x :real^N)$i)` THEN
  ASM_SIMP_TAC[dist; 
COMPONENT_LE_NORM] THEN
  ASM_SIMP_TAC[
VECTOR_SUB_COMPONENT; REAL_ARITH
   `x < &0 /\ &0 <= y ==> abs(x) <= abs(y - x)`]);;
 
 
let FINITE_SET_AVOID = prove
 (`!a:real^N s. 
FINITE s
                ==> ?d. &0 < d /\ !x. x 
IN s /\ ~(x = a) ==> d <= dist(a,x)`,
  GEN_TAC THEN MATCH_MP_TAC 
FINITE_INDUCT_STRONG THEN
  REWRITE_TAC[
NOT_IN_EMPTY] THEN
  CONJ_TAC THENL [MESON_TAC[
REAL_LT_01]; ALL_TAC] THEN
  MAP_EVERY X_GEN_TAC [`x:real^N`; `s:real^N->bool`] THEN
  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
  FIRST_X_ASSUM(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  ASM_CASES_TAC `x:real^N = a` THEN REWRITE_TAC[
IN_INSERT] THENL
   [ASM_MESON_TAC[]; ALL_TAC] THEN
  EXISTS_TAC `min d (dist(a:real^N,x))` THEN
  ASM_REWRITE_TAC[
REAL_LT_MIN; GSYM 
DIST_NZ; 
REAL_MIN_LE] THEN
  ASM_MESON_TAC[
REAL_LE_REFL]);;
 
 
let DISCRETE_IMP_CLOSED = prove
 (`!s:real^N->bool e.
        &0 < e /\
        (!x y. x 
IN s /\ y 
IN s /\ norm(y - x) < e ==> y = x)
        ==> closed s`,
  REPEAT STRIP_TAC THEN
  SUBGOAL_THEN `!x:real^N. ~(x 
limit_point_of s)`
    (fun th -> MESON_TAC[th; 
CLOSED_LIMPT]) THEN
  GEN_TAC THEN REWRITE_TAC[
LIMPT_APPROACHABLE] THEN DISCH_TAC THEN
  FIRST_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  REWRITE_TAC[
REAL_HALF; ASSUME `&0 < e`] THEN
  DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `min (e / &2) (dist(x:real^N,y))`) THEN
  ASM_SIMP_TAC[
REAL_LT_MIN; 
DIST_POS_LT; 
REAL_HALF] THEN
  DISCH_THEN(X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`y:real^N`; `z:real^N`]) THEN
  ASM_REWRITE_TAC[] THEN ASM_NORM_ARITH_TAC);;
 
 
let LIMPT_OF_OPEN_IN = prove
 (`!s t x:real^N.
        
open_in (subtopology euclidean s) t /\ x 
limit_point_of s /\ x 
IN t
        ==> x 
limit_point_of t`,
  REWRITE_TAC[
open_in; 
SUBSET; 
LIMPT_APPROACHABLE] THEN
  REPEAT GEN_TAC THEN STRIP_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `min d e / &2`) THEN
  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; MATCH_MP_TAC 
MONO_EXISTS] THEN
  GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THEN
  TRY(FIRST_X_ASSUM MATCH_MP_TAC) THEN ASM_REWRITE_TAC[] THEN
  ASM_REAL_ARITH_TAC);;
 
 
(* ------------------------------------------------------------------------- *)
(* Interior of a set.                                                        *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Closure of a set.                                                         *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* A variant of nets (slightly non-standard but good for our purposes).      *)
(* ------------------------------------------------------------------------- *)
let net_tybij = new_type_definition "net" ("mk_net","netord")
 (prove
   (`?g:A->A->bool. !x y. (!z. g z x ==> g z y) \/ (!z. g z y ==> g z x)`,
    EXISTS_TAC `\x:A y:A. F` THEN REWRITE_TAC[]));;
let NET = prove
 (`!n x y. (!z. netord n z x ==> netord n z y) \/
           (!z. netord n z y ==> netord n z x)`,
   REWRITE_TAC[net_tybij; ETA_AX]);;
 
 
let OLDNET = prove
 (`!n x y. netord n x x /\ netord n y y
           ==> ?z. netord n z z /\
                   !w. netord n w z ==> netord n w x /\ netord n w y`,
 
 
let NET_DILEMMA = prove
 (`!net. (?a. (?x. netord net x a) /\ (!x. netord net x a ==> P x)) /\
         (?b. (?x. netord net x b) /\ (!x. netord net x b ==> Q x))
         ==> ?c. (?x. netord net x c) /\ (!x. netord net x c ==> P x /\ Q x)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Common nets and the "within" modifier for nets.                           *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("within",(14,"right"));;
parse_as_infix("in_direction",(14,"right"));;
(* ------------------------------------------------------------------------- *)
(* Prove that they are all nets.                                             *)
(* ------------------------------------------------------------------------- *)
let NET_PROVE_TAC[def] =
  REWRITE_TAC[GSYM FUN_EQ_THM; def] THEN
  REWRITE_TAC[ETA_AX] THEN
  ASM_SIMP_TAC[GSYM(CONJUNCT2 net_tybij)];;
let AT = prove
 (`!a:real^N x y.
        netord(at a) x y <=> &0 < dist(x,a) /\ dist(x,a) <= dist(y,a)`,
 
 
let WITHIN = prove
 (`!n s x y. netord(n within s) x y <=> netord n x y /\ x 
IN s`,
  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[within; GSYM 
FUN_EQ_THM] THEN
  REWRITE_TAC[GSYM(CONJUNCT2 net_tybij); ETA_AX] THEN
  MESON_TAC[
NET]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Identify trivial limits, where we can't approach arbitrarily closely.     *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Some property holds "sufficiently close" to the limit point.              *)
(* ------------------------------------------------------------------------- *)
let EVENTUALLY_WITHIN_LE = prove
 (`!s a:real^M p.
     eventually p (at a within s) <=>
        ?d. &0 < d /\ !x. x 
IN s /\ &0 < dist(x,a) /\ dist(x,a) <= d ==> p(x)`,
 
 
let EVENTUALLY_WITHIN = prove
 (`!s a:real^M p.
     eventually p (at a within s) <=>
        ?d. &0 < d /\ !x. x 
IN s /\ &0 < dist(x,a) /\ dist(x,a) < d ==> p(x)`,
 
 
let EVENTUALLY_AT = prove
 (`!a p. eventually p (at a) <=>
         ?d. &0 < d /\ !x. &0 < dist(x,a) /\ dist(x,a) < d ==> p(x)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Combining theorems for "eventually".                                      *)
(* ------------------------------------------------------------------------- *)
let EVENTUALLY_AND = prove
 (`!net:(A net) p q.
        eventually (\x. p x /\ q x) net <=>
        eventually p net /\ eventually q net`,
  REPEAT GEN_TAC THEN REWRITE_TAC[eventually] THEN
  ASM_CASES_TAC `
trivial_limit(net:(A net))` THEN ASM_REWRITE_TAC[] THEN
  EQ_TAC THEN SIMP_TAC[
NET_DILEMMA] THEN MESON_TAC[]);;
 
 
let EVENTUALLY_MONO = prove
 (`!net:(A net) p q.
        (!x. p x ==> q x) /\ eventually p net
        ==> eventually q net`,
  REWRITE_TAC[eventually] THEN MESON_TAC[]);;
 
 
let EVENTUALLY_MP = prove
 (`!net:(A net) p q.
        eventually (\x. p x ==> q x) net /\ eventually p net
        ==> eventually q net`,
  REWRITE_TAC[GSYM 
EVENTUALLY_AND] THEN
  REWRITE_TAC[eventually] THEN MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Limits, defined as vacuously true when the limit is trivial.              *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("-->",(12,"right"));;
let LIM = prove
 (`(f --> l) net <=>
        
trivial_limit net \/
        !e. &0 < e ==> ?y. (?x. netord(net) x y) /\
                           !x. netord(net) x y ==> dist(f(x),l) < e`,
  REWRITE_TAC[tendsto; eventually] THEN MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Show that they yield usual definitions in the various cases.              *)
(* ------------------------------------------------------------------------- *)
let LIM_WITHIN_LE = prove
 (`!f:real^M->real^N l a s.
        (f --> l)(at a within s) <=>
           !e. &0 < e ==> ?d. &0 < d /\
                              !x. x 
IN s /\ &0 < dist(x,a) /\ dist(x,a) <= d
                                   ==> dist(f(x),l) < e`,
 
 
let LIM_WITHIN = prove
 (`!f:real^M->real^N l a s.
      (f --> l) (at a within s) <=>
        !e. &0 < e
            ==> ?d. &0 < d /\
                    !x. x 
IN s /\ &0 < dist(x,a) /\ dist(x,a) < d
                    ==> dist(f(x),l) < e`,
 
 
let LIM_AT_LE = prove
 (`!f l a. (f --> l) (at a) <=>
           !e. &0 < e
               ==> ?d. &0 < d /\
                       !x. &0 < dist(x,a) /\ dist(x,a) <= d
                           ==> dist (f x,l) < e`,
 
 
let LIM_AT = prove
 (`!f l:real^N a:real^M.
      (f --> l) (at a) <=>
              !e. &0 < e
                  ==> ?d. &0 < d /\ !x. &0 < dist(x,a) /\ dist(x,a) < d
                          ==> dist(f(x),l) < e`,
 
 
(* ------------------------------------------------------------------------- *)
(* The expected monotonicity property.                                       *)
(* ------------------------------------------------------------------------- *)
let LIM_UNION = prove
 (`!f x l s t.
        (f --> l) (at x within s) /\ (f --> l) (at x within t)
        ==> (f --> l) (at x within (s 
UNION t))`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
LIM_WITHIN; 
IN_UNION] THEN
  REWRITE_TAC[
AND_FORALL_THM] THEN MATCH_MP_TAC 
MONO_FORALL THEN
  X_GEN_TAC `e:real` THEN ASM_CASES_TAC `&0 < e` THEN ASM_SIMP_TAC[] THEN
  DISCH_THEN(CONJUNCTS_THEN2
   (X_CHOOSE_TAC `d1:real`) (X_CHOOSE_TAC `d2:real`)) THEN
  EXISTS_TAC `min d1 d2` THEN ASM_MESON_TAC[
REAL_LT_MIN]);;
 
 
let LIM_UNION_UNIV = prove
 (`!f x l s t.
        (f --> l) (at x within s) /\ (f --> l) (at x within t) /\
        s 
UNION t = (:real^N)
        ==> (f --> l) (at x)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Composition of limits.                                                    *)
(* ------------------------------------------------------------------------- *)
let LIM_COMPOSE_WITHIN = prove
 (`!net f:real^M->real^N g:real^N->real^P s y z.
    (f --> y) net /\
    eventually (\w. f w 
IN s /\ (f w = y ==> g y = z)) net /\
    (g --> z) (at y within s)
    ==> ((g o f) --> z) net`,
 
 
let LIM_COMPOSE_AT = prove
 (`!net f:real^M->real^N g:real^N->real^P y z.
    (f --> y) net /\
    eventually (\w. f w = y ==> g y = z) net /\
    (g --> z) (at y)
    ==> ((g o f) --> z) net`,
  REPEAT STRIP_TAC THEN
  MP_TAC(ISPECL [`net:(real^M)net`; `f:real^M->real^N`; `g:real^N->real^P`;
                 `(:real^N)`; `y:real^N`; `z:real^P`]
        
LIM_COMPOSE_WITHIN) THEN
  ASM_REWRITE_TAC[
IN_UNIV; 
WITHIN_UNIV]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Interrelations between restricted and unrestricted limits.                *)
(* ------------------------------------------------------------------------- *)
let LIM_WITHIN_OPEN = prove
 (`!f l a:real^M s.
     a 
IN s /\ open s ==> ((f --> l)(at a within s) <=> (f --> l)(at a))`,
  REPEAT STRIP_TAC THEN EQ_TAC THEN SIMP_TAC[
LIM_AT_WITHIN] THEN
  REWRITE_TAC[
LIM_AT; 
LIM_WITHIN] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `e:real` THEN
  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
   DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `a:real^M` o GEN_REWRITE_RULE I [
open_def]) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL [`d1:real`; `d2:real`] 
REAL_DOWN2) THEN ASM_REWRITE_TAC[] THEN
  ASM_MESON_TAC[
REAL_LT_TRANS]);;
 
 
(* ------------------------------------------------------------------------- *)
(* More limit point characterizations.                                       *)
(* ------------------------------------------------------------------------- *)
let [LIMPT_INFINITE_OPEN; LIMPT_INFINITE_BALL; LIMPT_INFINITE_CBALL] =
    (CONJUNCTS o prove)
 (`(!s x:real^N.
        x limit_point_of s <=> !t. x IN t /\ open t ==> INFINITE(s INTER t)) /\
   (!s x:real^N.
        x limit_point_of s <=> !e. &0 < e ==> INFINITE(s INTER ball(x,e))) /\
   (!s x:real^N.
        x limit_point_of s <=> !e. &0 < e ==> INFINITE(s INTER cball(x,e)))`,
  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT
   `(q ==> p) /\ (r ==> s) /\ (s ==> q) /\ (p ==> r)
    ==> (p <=> q) /\ (p <=> r) /\ (p <=> s)`) THEN
  REPEAT CONJ_TAC THENL
   [REWRITE_TAC[limit_point_of; INFINITE; SET_RULE
     `(?y. ~(y = x) /\ y IN s /\ y IN t) <=> ~(s INTER t SUBSET {x})`] THEN
    MESON_TAC[FINITE_SUBSET; FINITE_SING];
    MESON_TAC[INFINITE_SUPERSET; BALL_SUBSET_CBALL;
              SET_RULE `t SUBSET u ==> s INTER t SUBSET s INTER u`];
    MESON_TAC[INFINITE_SUPERSET; OPEN_CONTAINS_CBALL;
              SET_RULE `t SUBSET u ==> s INTER t SUBSET s INTER u`];
    REWRITE_TAC[LIMPT_SEQUENTIAL_INJ; IN_DELETE; FORALL_AND_THM] THEN
    DISCH_THEN(X_CHOOSE_THEN `f:num->real^N` STRIP_ASSUME_TAC) THEN
    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_SEQUENTIALLY]) THEN
    DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
    ASM_REWRITE_TAC[GSYM(ONCE_REWRITE_RULE[DIST_SYM] IN_BALL)] THEN
    DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN
    MATCH_MP_TAC INFINITE_SUPERSET THEN
    EXISTS_TAC `IMAGE (f:num->real^N) (from N)` THEN
    ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_FROM; IN_INTER] THEN
    ASM_MESON_TAC[INFINITE_IMAGE_INJ; INFINITE_FROM]]);;
let INFINITE_OPEN_IN = prove
 (`!u s:real^N->bool.
      
open_in (subtopology euclidean u) s /\ (?x. x 
IN s /\ x 
limit_point_of u)
      ==> 
INFINITE s`,
  REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
OPEN_IN_OPEN]) THEN
  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `t:real^N->bool` o
        GEN_REWRITE_RULE I [LIMPT_INFINITE_OPEN]) THEN
  FIRST_X_ASSUM SUBST_ALL_TAC THEN ASM SET_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Condensation points.                                                      *)
(* ------------------------------------------------------------------------- *)
parse_as_infix ("condensation_point_of",(12,"right"));;
let CONDENSATION_POINT_INFINITE_BALL,CONDENSATION_POINT_INFINITE_CBALL =
  (CONJ_PAIR o prove)
 (`(!s x:real^N.
        x condensation_point_of s <=>
        !e. &0 < e ==> ~COUNTABLE(s INTER ball(x,e))) /\
   (!s x:real^N.
        x condensation_point_of s <=>
        !e. &0 < e ==> ~COUNTABLE(s INTER cball(x,e)))`,
  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT
   `(p ==> q) /\ (q ==> r) /\ (r ==> p)
    ==> (p <=> q) /\ (p <=> r)`) THEN
  REWRITE_TAC[condensation_point_of] THEN REPEAT CONJ_TAC THENL
   [MESON_TAC[OPEN_BALL; CENTRE_IN_BALL];
    MESON_TAC[BALL_SUBSET_CBALL; COUNTABLE_SUBSET;
              SET_RULE `t SUBSET u ==> s INTER t SUBSET s INTER u`];
    MESON_TAC[COUNTABLE_SUBSET; OPEN_CONTAINS_CBALL;
              SET_RULE `t SUBSET u ==> s INTER t SUBSET s INTER u`]]);;
(* ------------------------------------------------------------------------- *)
(* Basic arithmetical combining theorems for limits.                         *)
(* ------------------------------------------------------------------------- *)
let LIM_LINEAR = prove
 (`!net:(A)net h f l.
        (f --> l) net /\ linear h ==> ((\x. h(f x)) --> h l) net`,
 
 
let LIM_CMUL = prove
 (`!f l c. (f --> l) net ==> ((\x. c % f x) --> c % l) net`,
 
 
let LIM_CMUL_EQ = prove
 (`!net f l c.
        ~(c = &0) ==> (((\x. c % f x) --> c % l) net <=> (f --> l) net)`,
 
 
let LIM_NEG = prove
 (`!net f l:real^N. (f --> l) net ==> ((\x. --(f x)) --> --l) net`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
LIM; dist] THEN
  REWRITE_TAC[VECTOR_ARITH `--x - --y = --(x - y:real^N)`; 
NORM_NEG]);;
 
 
let LIM_NEG_EQ = prove
 (`!net f l:real^N. ((\x. --(f x)) --> --l) net <=> (f --> l) net`,
  REPEAT GEN_TAC THEN EQ_TAC THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
LIM_NEG) THEN
  REWRITE_TAC[
VECTOR_NEG_NEG; ETA_AX]);;
 
 
let LIM_ADD = prove
 (`!net:(A)net f g l m.
    (f --> l) net /\ (g --> m) net ==> ((\x. f(x) + g(x)) --> l + m) net`,
 
 
let LIM_ABS = prove
 (`!net:(A)net f:A->real^N l.
     (f --> l) net
     ==> ((\x. lambda i. (abs(f(x)$i))) --> (lambda i. abs(l$i)):real^N) net`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
LIM] THEN
  ASM_CASES_TAC `
trivial_limit (net:(A)net)` THEN ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN GEN_TAC THEN
  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN GEN_TAC THEN
  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN GEN_TAC THEN
  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
  MATCH_MP_TAC(NORM_ARITH
   `norm(x - y) <= norm(a - b) ==> dist(a,b) < e ==> dist(x,y) < e`) THEN
  MATCH_MP_TAC 
NORM_LE_COMPONENTWISE THEN
  SIMP_TAC[
LAMBDA_BETA; 
VECTOR_SUB_COMPONENT] THEN
  REAL_ARITH_TAC);;
 
 
let LIM_SUB = prove
 (`!net:(A)net f g l m.
    (f --> l) net /\ (g --> m) net ==> ((\x. f(x) - g(x)) --> l - m) net`,
 
 
let LIM_MAX = prove
 (`!net:(A)net f g l:real^N m:real^N.
    (f --> l) net /\ (g --> m) net
    ==> ((\x. lambda i. max (f(x)$i) (g(x)$i))
         --> (lambda i. max (l$i) (m$i)):real^N) net`,
 
 
let LIM_MIN = prove
 (`!net:(A)net f g l:real^N m:real^N.
    (f --> l) net /\ (g --> m) net
    ==> ((\x. lambda i. min (f(x)$i) (g(x)$i))
         --> (lambda i. min (l$i) (m$i)):real^N) net`,
 
 
let LIM_NORM = prove
 (`!net f:A->real^N l.
        (f --> l) net ==> ((\x. lift(norm(f x))) --> lift(norm l)) net`,
  REPEAT GEN_TAC THEN REWRITE_TAC[tendsto; 
DIST_LIFT] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN
  REWRITE_TAC[] THEN
  MATCH_MP_TAC(REWRITE_RULE[
IMP_CONJ] 
EVENTUALLY_MONO) THEN
  REWRITE_TAC[] THEN NORM_ARITH_TAC);;
 
 
let LIM_NULL = prove
 (`!net f l. (f --> l) net <=> ((\x. f(x) - l) --> vec 0) net`,
 
 
let LIM_NULL_COMPARISON = prove
 (`!net f g. eventually (\x. norm(f x) <= g x) net /\
             ((\x. lift(g x)) --> vec 0) net
             ==> (f --> vec 0) net`,
 
 
let LIM_COMPONENT = prove
 (`!net f i l:real^N. (f --> l) net /\ 1 <= i /\ i <= dimindex(:N)
                      ==> ((\a. lift(f(a)$i)) --> lift(l$i)) net`,
 
 
let LIM_NULL_CMUL_BOUNDED = prove
 (`!f g:A->real^N B.
        eventually (\a. g a = vec 0 \/ abs(f a) <= B) net /\
        (g --> vec 0) net
        ==> ((\n. f n % g n) --> vec 0) net`,
 
 
let LIM_NULL_VMUL_BOUNDED = prove
 (`!f g:A->real^N B.
        ((lift o f) --> vec 0) net /\
        eventually (\a. f a = &0 \/ norm(g a) <= B) net
        ==> ((\n. f n % g n) --> vec 0) net`,
 
 
let LIM_VSUM = prove
 (`!f:A->B->real^N s.
        
FINITE s /\ (!i. i 
IN s ==> ((f i) --> (l i)) net)
        ==> ((\x. vsum s (\i. f i x)) --> vsum s l) net`,
 
 
(* ------------------------------------------------------------------------- *)
(* Deducing things about the limit from the elements.                        *)
(* ------------------------------------------------------------------------- *)
let LIM_IN_CLOSED_SET = prove
 (`!net f:A->real^N s l.
        closed s /\ eventually (\x. f(x) 
IN s) net /\
        ~(
trivial_limit net) /\ (f --> l) net
        ==> l 
IN s`,
  REWRITE_TAC[closed] THEN REPEAT STRIP_TAC THEN
  MATCH_MP_TAC(SET_RULE `~(x 
IN (
UNIV DIFF s)) ==> x 
IN s`) THEN
  DISCH_TAC THEN
  FIRST_ASSUM(MP_TAC o SPEC `l:real^N` o GEN_REWRITE_RULE I
          [
OPEN_CONTAINS_BALL]) THEN
  ASM_REWRITE_TAC[
SUBSET; 
IN_BALL; 
IN_DIFF; 
IN_UNION] THEN
  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e:real` o GEN_REWRITE_RULE I [tendsto]) THEN
  UNDISCH_TAC `eventually (\x. (f:A->real^N) x 
IN s) net` THEN
  ASM_REWRITE_TAC[GSYM 
EVENTUALLY_AND; TAUT `a ==> ~b <=> ~(a /\ b)`] THEN
  MATCH_MP_TAC 
NOT_EVENTUALLY THEN ASM_MESON_TAC[
DIST_SYM]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Need to prove closed(cball(x,e)) before deducing this as a corollary.     *)
(* ------------------------------------------------------------------------- *)
let LIM_NORM_UBOUND = prove
 (`!net:(A)net f (l:real^N) b.
      ~(
trivial_limit net) /\
      (f --> l) net /\
      eventually (\x. norm(f x) <= b) net
      ==> norm(l) <= b`,
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  ASM_REWRITE_TAC[
LIM] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  ASM_REWRITE_TAC[eventually] THEN
  STRIP_TAC THEN REWRITE_TAC[GSYM 
REAL_NOT_LT] THEN
  ONCE_REWRITE_TAC[GSYM 
REAL_SUB_LT] THEN DISCH_TAC THEN
  SUBGOAL_THEN
   `?x:A. dist(f(x):real^N,l) < norm(l:real^N) - b /\ norm(f x) <= b`
  (CHOOSE_THEN MP_TAC) THENL [ASM_MESON_TAC[
NET]; ALL_TAC] THEN
  REWRITE_TAC[
REAL_NOT_LT; 
REAL_LE_SUB_RADD; DE_MORGAN_THM; dist] THEN
  NORM_ARITH_TAC);;
 
 
let LIM_NORM_LBOUND = prove
 (`!net:(A)net f (l:real^N) b.
      ~(
trivial_limit net) /\ (f --> l) net /\
      eventually (\x. b <= norm(f x)) net
      ==> b <= norm(l)`,
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  ASM_REWRITE_TAC[
LIM] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  ASM_REWRITE_TAC[eventually] THEN
  STRIP_TAC THEN REWRITE_TAC[GSYM 
REAL_NOT_LT] THEN
  ONCE_REWRITE_TAC[GSYM 
REAL_SUB_LT] THEN DISCH_TAC THEN
  SUBGOAL_THEN
   `?x:A. dist(f(x):real^N,l) < b - norm(l:real^N) /\ b <= norm(f x)`
  (CHOOSE_THEN MP_TAC) THENL [ASM_MESON_TAC[
NET]; ALL_TAC] THEN
  REWRITE_TAC[
REAL_NOT_LT; 
REAL_LE_SUB_RADD; DE_MORGAN_THM; dist] THEN
  NORM_ARITH_TAC);;
 
 
(* ------------------------------------------------------------------------- *)
(* Uniqueness of the limit, when nontrivial.                                 *)
(* ------------------------------------------------------------------------- *)
let LIM_UNIQUE = prove
 (`!net:(A)net f l:real^N l'.
      ~(
trivial_limit net) /\ (f --> l) net /\ (f --> l') net ==> (l = l')`,
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  DISCH_THEN(ASSUME_TAC o REWRITE_RULE[
VECTOR_SUB_REFL] o MATCH_MP 
LIM_SUB) THEN
  SUBGOAL_THEN `!e. &0 < e ==> norm(l:real^N - l') <= e` MP_TAC THENL
   [GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC 
LIM_NORM_UBOUND THEN
    MAP_EVERY EXISTS_TAC [`net:(A)net`; `\x:A. vec 0 : real^N`] THEN
    ASM_SIMP_TAC[
NORM_0; 
REAL_LT_IMP_LE; eventually] THEN
    ASM_MESON_TAC[
trivial_limit];
    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[
DIST_NZ; dist] THEN
    DISCH_TAC THEN DISCH_THEN(MP_TAC o SPEC `norm(l - l':real^N) / &2`) THEN
    ASM_SIMP_TAC[
REAL_LT_RDIV_EQ; 
REAL_LE_RDIV_EQ; 
REAL_OF_NUM_LT; ARITH] THEN
    UNDISCH_TAC `&0 < norm(l - l':real^N)` THEN REAL_ARITH_TAC]);;
 
 
let LIM_CONST_EQ = prove
 (`!net:(A net) c d:real^N.
        ((\x. c) --> d) net <=> 
trivial_limit net \/ c = d`,
  REPEAT GEN_TAC THEN
  ASM_CASES_TAC `
trivial_limit (net:A net)` THEN ASM_REWRITE_TAC[] THENL
   [ASM_REWRITE_TAC[
LIM]; ALL_TAC] THEN
  EQ_TAC THEN SIMP_TAC[
LIM_CONST] THEN DISCH_TAC THEN
  MATCH_MP_TAC(SPEC `net:A net` 
LIM_UNIQUE) THEN
  EXISTS_TAC `(\x. c):A->real^N` THEN ASM_REWRITE_TAC[
LIM_CONST]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Some unwieldy but occasionally useful theorems about uniform limits.      *)
(* ------------------------------------------------------------------------- *)
let UNIFORM_LIM_ADD = prove
 (`!net:(A)net P f g l m.
        (!e. &0 < e
             ==> eventually (\x. !n:B. P n ==> norm(f n x - l n) < e) net) /\
        (!e. &0 < e
             ==> eventually (\x. !n. P n ==> norm(g n x - m n) < e) net)
        ==> !e. &0 < e
                ==> eventually
                     (\x. !n. P n
                              ==> norm((f n x + g n x) - (l n + m n)) < e)
                     net`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
AND_FORALL_THM] THEN DISCH_TAC THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  ASM_REWRITE_TAC[
REAL_HALF; GSYM 
EVENTUALLY_AND] THEN
  MATCH_MP_TAC(REWRITE_RULE[
IMP_CONJ] 
EVENTUALLY_MONO) THEN
  GEN_TAC THEN REWRITE_TAC[
AND_FORALL_THM] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `n:B` THEN
  ASM_CASES_TAC `(P:B->bool) n` THEN ASM_REWRITE_TAC[] THEN
  CONV_TAC NORM_ARITH);;
 
 
let UNIFORM_LIM_SUB = prove
 (`!net:(A)net P f g l m.
        (!e. &0 < e
             ==> eventually (\x. !n:B. P n ==> norm(f n x - l n) < e) net) /\
        (!e. &0 < e
             ==> eventually (\x. !n. P n ==> norm(g n x - m n) < e) net)
        ==> !e. &0 < e
                ==> eventually
                     (\x. !n. P n
                              ==> norm((f n x - g n x) - (l n - m n)) < e)
                     net`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
AND_FORALL_THM] THEN DISCH_TAC THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  ASM_REWRITE_TAC[
REAL_HALF; GSYM 
EVENTUALLY_AND] THEN
  MATCH_MP_TAC(REWRITE_RULE[
IMP_CONJ] 
EVENTUALLY_MONO) THEN
  GEN_TAC THEN REWRITE_TAC[
AND_FORALL_THM] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `n:B` THEN
  ASM_CASES_TAC `(P:B->bool) n` THEN ASM_REWRITE_TAC[] THEN
  CONV_TAC NORM_ARITH);;
 
 
(* ------------------------------------------------------------------------- *)
(* Limit under bilinear function, uniform version first.                     *)
(* ------------------------------------------------------------------------- *)
let UNIFORM_LIM_BILINEAR = prove
 (`!net:(A)net P (h:real^M->real^N->real^P) f g l m b1 b2.
        bilinear h /\
        eventually (\x. !n. P n ==> norm(l n) <= b1) net /\
        eventually (\x. !n. P n ==> norm(m n) <= b2) net /\
        (!e. &0 < e
             ==> eventually (\x. !n:B. P n ==> norm(f n x - l n) < e) net) /\
        (!e. &0 < e
             ==> eventually (\x. !n. P n ==> norm(g n x - m n) < e) net)
        ==> !e. &0 < e
                ==> eventually
                     (\x. !n. P n
                              ==> norm(h (f n x) (g n x) - h (l n) (m n)) < e)
                     net`,
  REPEAT GEN_TAC THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  FIRST_ASSUM(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC o  MATCH_MP
   
BILINEAR_BOUNDED_POS) THEN
  REWRITE_TAC[
AND_FORALL_THM; 
RIGHT_AND_FORALL_THM] THEN DISCH_TAC THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC
   `min (abs b2 + &1) (e / &2 / (B * (abs b1 + abs b2 + &2)))`) THEN
  ASM_SIMP_TAC[
REAL_HALF; 
REAL_LT_DIV; 
REAL_LT_MUL; 
REAL_LT_MIN;
               REAL_ARITH `&0 < abs x + &1`;
               REAL_ARITH `&0 < abs x + abs y + &2`] THEN
  REWRITE_TAC[GSYM 
EVENTUALLY_AND] THEN
  MATCH_MP_TAC(REWRITE_RULE[
IMP_CONJ] 
EVENTUALLY_MONO) THEN
  X_GEN_TAC `x:A` THEN REWRITE_TAC[
AND_FORALL_THM] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `n:B` THEN
  ASM_CASES_TAC `(P:B->bool) n` THEN ASM_REWRITE_TAC[] THEN
  STRIP_TAC THEN
  ONCE_REWRITE_TAC[VECTOR_ARITH
    `h a b - h c d :real^N = (h a b - h a d) + (h a d - h c d)`] THEN
  ASM_SIMP_TAC[GSYM 
BILINEAR_LSUB; GSYM 
BILINEAR_RSUB] THEN
  MATCH_MP_TAC 
NORM_TRIANGLE_LT THEN
  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
   (MESON[
REAL_LE_ADD2; 
REAL_LET_TRANS]
     `(!x y. norm(h x y:real^P) <= B * norm x * norm y)
       ==> B * norm a * norm b + B * norm c * norm d < e
           ==> norm(h a b) + norm(h c d) < e`)) THEN
  MATCH_MP_TAC(REAL_ARITH
   `x * B < e / &2 /\ y * B < e / &2 ==> B * x + B * y < e`) THEN
  CONJ_TAC THEN ASM_SIMP_TAC[GSYM 
REAL_LT_RDIV_EQ] THENL
   [ONCE_REWRITE_TAC[REAL_MUL_SYM]; ALL_TAC] THEN
  MATCH_MP_TAC 
REAL_LET_TRANS THEN
  EXISTS_TAC `e / &2 / (B * (abs b1 + abs b2 + &2)) *
             (abs b1 + abs b2 + &1)` THEN
  (CONJ_TAC THENL
    [MATCH_MP_TAC 
REAL_LE_MUL2 THEN
     ASM_SIMP_TAC[
NORM_POS_LE; 
REAL_LT_IMP_LE] THEN
     ASM_SIMP_TAC[REAL_ARITH `a <= b2 ==> a <= abs b1 + abs b2 + &1`] THEN
     ASM_MESON_TAC[NORM_ARITH
       `norm(f - l:real^P) < abs b2 + &1 /\ norm(l) <= b1
        ==> norm(f) <= abs b1 + abs b2 + &1`];
     ONCE_REWRITE_TAC[
real_div] THEN
     ASM_SIMP_TAC[
REAL_LT_LMUL_EQ; 
REAL_HALF; GSYM REAL_MUL_ASSOC;
                  
REAL_INV_MUL] THEN
     REWRITE_TAC[REAL_ARITH `B * inv x * y < B <=> B * y / x < B * &1`] THEN
     ASM_SIMP_TAC[
REAL_LT_INV_EQ; 
REAL_LT_LMUL_EQ; 
REAL_LT_LDIV_EQ;
                  REAL_ARITH `&0 < abs x + abs y + &2`] THEN
     REAL_ARITH_TAC]));;
 
 
let LIM_BILINEAR = prove
 (`!net:(A)net (h:real^M->real^N->real^P) f g l m.
        (f --> l) net /\ (g --> m) net /\ bilinear h
        ==> ((\x. h (f x) (g x)) --> (h l m)) net`,
  REPEAT STRIP_TAC THEN
  MP_TAC(ISPECL
   [`net:(A)net`; `\x:one. T`; `h:real^M->real^N->real^P`;
    `\n:one. (f:A->real^M)`; `\n:one. (g:A->real^N)`;
    `\n:one. (l:real^M)`; `\n:one. (m:real^N)`;
    `norm(l:real^M)`; `norm(m:real^N)`]
   
UNIFORM_LIM_BILINEAR) THEN
  ASM_REWRITE_TAC[
REAL_LE_REFL; 
EVENTUALLY_TRUE] THEN
  ASM_REWRITE_TAC[GSYM dist; GSYM tendsto]);;
 
 
(* ------------------------------------------------------------------------- *)
(* These are special for limits out of the same vector space.                *)
(* ------------------------------------------------------------------------- *)
let LIM_AT_ZERO = prove
 (`!f:real^M->real^N l a.
        (f --> l) (at a) <=> ((\x. f(a + x)) --> l) (at(vec 0))`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
LIM_AT] THEN
  AP_TERM_TAC THEN ABS_TAC THEN
  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
  AP_TERM_TAC THEN ABS_TAC THEN
  ASM_CASES_TAC `&0 < d` THEN ASM_REWRITE_TAC[] THEN
  EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `x:real^M` THENL
   [FIRST_X_ASSUM(MP_TAC o SPEC `a + x:real^M`) THEN
    REWRITE_TAC[dist; 
VECTOR_ADD_SUB; 
VECTOR_SUB_RZERO];
    FIRST_X_ASSUM(MP_TAC o SPEC `x - a:real^M`) THEN
    REWRITE_TAC[dist; 
VECTOR_SUB_RZERO; 
VECTOR_SUB_ADD2]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* It's also sometimes useful to extract the limit point from the net.       *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Transformation of limit.                                                  *)
(* ------------------------------------------------------------------------- *)
let LIM_TRANSFORM = prove
 (`!net f g l.
     ((\x. f x - g x) --> vec 0) net /\ (f --> l) net ==> (g --> l) net`,
  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP 
LIM_SUB) THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
LIM_NEG) THEN MATCH_MP_TAC EQ_IMP THEN
  AP_THM_TAC THEN BINOP_TAC THEN REWRITE_TAC[
FUN_EQ_THM] THEN
  VECTOR_ARITH_TAC);;
 
 
let LIM_TRANSFORM_WITHIN = prove
 (`!f g x s d.
        &0 < d /\
        (!x'. x' 
IN s /\ &0 < dist(x',x) /\ dist(x',x) < d ==> f(x') = g(x')) /\
        (f --> l) (at x within s)
        ==> (g --> l) (at x within s)`,
 
 
let LIM_TRANSFORM_AT = prove
 (`!f g x d.
        &0 < d /\
        (!x'. &0 < dist(x',x) /\ dist(x',x) < d ==> f(x') = g(x')) /\
        (f --> l) (at x)
        ==> (g --> l) (at x)`,
 
 
let LIM_TRANSFORM_EQ = prove
 (`!net f:A->real^N g l.
     ((\x. f x - g x) --> vec 0) net ==> ((f --> l) net <=> (g --> l) net)`,
  REPEAT STRIP_TAC THEN EQ_TAC THEN
  DISCH_TAC THEN MATCH_MP_TAC 
LIM_TRANSFORM THENL
   [EXISTS_TAC `f:A->real^N` THEN ASM_REWRITE_TAC[];
    EXISTS_TAC `g:A->real^N` THEN ASM_REWRITE_TAC[] THEN
    ONCE_REWRITE_TAC[GSYM 
LIM_NEG_EQ] THEN
    ASM_REWRITE_TAC[
VECTOR_NEG_SUB; 
VECTOR_NEG_0]]);;
 
 
let LIM_TRANSFORM_WITHIN_SET = prove
 (`!f a s t.
        eventually (\x. x 
IN s <=> x 
IN t) (at a)
        ==> ((f --> l) (at a within s) <=> (f --> l) (at a within t))`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
EVENTUALLY_AT; 
LIM_WITHIN] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `min d k:real` THEN ASM_REWRITE_TAC[
REAL_LT_MIN] THEN
  ASM_MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Common case assuming being away from some crucial point like 0.           *)
(* ------------------------------------------------------------------------- *)
let LIM_TRANSFORM_AWAY_WITHIN = prove
 (`!f:real^M->real^N g a b s.
        ~(a = b) /\
        (!x. x 
IN s /\ ~(x = a) /\ ~(x = b) ==> f(x) = g(x)) /\
        (f --> l) (at a within s)
        ==> (g --> l) (at a within s)`,
  REPEAT STRIP_TAC THEN MATCH_MP_TAC 
LIM_TRANSFORM_WITHIN THEN
  MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `dist(a:real^M,b)`] THEN
  ASM_REWRITE_TAC[GSYM 
DIST_NZ] THEN X_GEN_TAC `y:real^M` THEN
  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
  ASM_MESON_TAC[
DIST_SYM; 
REAL_LT_REFL]);;
 
 
let LIM_TRANSFORM_AWAY_AT = prove
 (`!f:real^M->real^N g a b.
        ~(a = b) /\
        (!x. ~(x = a) /\ ~(x = b) ==> f(x) = g(x)) /\
        (f --> l) (at a)
        ==> (g --> l) (at a)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Alternatively, within an open set.                                        *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Another quite common idiom of an explicit conditional in a sequence.      *)
(* ------------------------------------------------------------------------- *)
let LIM_CASES_SEQUENTIALLY = prove
 (`!f g l m. (((\n. if m <= n then f n else g n) --> l) sequentially <=>
              (f --> l) sequentially) /\
             (((\n. if m < n then f n else g n) --> l) sequentially <=>
              (f --> l) sequentially) /\
             (((\n. if n <= m then f n else g n) --> l) sequentially <=>
              (g --> l) sequentially) /\
             (((\n. if n < m then f n else g n) --> l) sequentially <=>
              (g --> l) sequentially)`,
 
 
(* ------------------------------------------------------------------------- *)
(* A congruence rule allowing us to transform limits assuming not at point.  *)
(* ------------------------------------------------------------------------- *)
let LIM_CONG_WITHIN = prove
 (`(!x. ~(x = a) ==> f x = g x)
   ==> (((\x. f x) --> l) (at a within s) <=> ((g --> l) (at a within s)))`,
 
 
let LIM_CONG_AT = prove
 (`(!x. ~(x = a) ==> f x = g x)
   ==> (((\x. f x) --> l) (at a) <=> ((g --> l) (at a)))`,
 
 
extend_basic_congs [LIM_CONG_WITHIN; LIM_CONG_AT];;
(* ------------------------------------------------------------------------- *)
(* Useful lemmas on closure and set of possible sequential limits.           *)
(* ------------------------------------------------------------------------- *)
let CLOSURE_SEQUENTIAL = prove
 (`!s l:real^N.
     l 
IN closure(s) <=> ?x. (!n. x(n) 
IN s) /\ (x --> l) sequentially`,
  REWRITE_TAC[closure; 
IN_UNION; 
LIMPT_SEQUENTIAL; 
IN_ELIM_THM; 
IN_DELETE] THEN
  REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT
    `((b ==> c) /\ (~a /\ c ==> b)) /\ (a ==> c) ==> (a \/ b <=> c)`) THEN
  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN DISCH_TAC THEN
  EXISTS_TAC `\n:num. l:real^N` THEN
  ASM_REWRITE_TAC[
LIM_CONST]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Some other lemmas about sequences.                                        *)
(* ------------------------------------------------------------------------- *)
let SEQ_OFFSET = prove
 (`!f l k. (f --> l) sequentially ==> ((\i. f(i + k)) --> l) sequentially`,
  REWRITE_TAC[
LIM_SEQUENTIALLY] THEN
  MESON_TAC[ARITH_RULE `N <= n ==> N <= n + k:num`]);;
 
 
let SEQ_OFFSET_NEG = prove
 (`!f l k. (f --> l) sequentially ==> ((\i. f(i - k)) --> l) sequentially`,
  REWRITE_TAC[
LIM_SEQUENTIALLY] THEN
  MESON_TAC[ARITH_RULE `N + k <= n ==> N <= n - k:num`]);;
 
 
let SEQ_OFFSET_REV = prove
 (`!f l k. ((\i. f(i + k)) --> l) sequentially ==> (f --> l) sequentially`,
  REWRITE_TAC[
LIM_SEQUENTIALLY] THEN
  MESON_TAC[ARITH_RULE `N + k <= n ==> N <= n - k /\ (n - k) + k = n:num`]);;
 
 
(* ------------------------------------------------------------------------- *)
(* More properties of closed balls.                                          *)
(* ------------------------------------------------------------------------- *)
let SPHERE_EQ_SING = prove
 (`!a:real^N r x. sphere(a,r) = {x} <=> x = a /\ r = &0`,
  REPEAT GEN_TAC THEN EQ_TAC THEN SIMP_TAC[
SPHERE_SING] THEN
  ASM_CASES_TAC `r < &0` THEN ASM_SIMP_TAC[
SPHERE_EMPTY; 
NOT_INSERT_EMPTY] THEN
  ASM_CASES_TAC `r = &0` THEN ASM_SIMP_TAC[
SPHERE_SING] THENL
   [ASM SET_TAC[]; ALL_TAC] THEN
  MATCH_MP_TAC(SET_RULE
   `!y. (x 
IN s ==> y 
IN s /\ ~(y = x)) ==> ~(s = {x})`) THEN
  EXISTS_TAC `a - (x - a):real^N` THEN REWRITE_TAC[
IN_SPHERE] THEN
  REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC NORM_ARITH);;
 
 
(* ------------------------------------------------------------------------- *)
(* For points in the interior, localization of limits makes no difference.   *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* A non-singleton connected set is perfect (i.e. has no isolated points).   *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Boundedness.                                                              *)
(* ------------------------------------------------------------------------- *)
let BOUNDED_CBALL = prove
 (`!x:real^N e. bounded(cball(x,e))`,
  REPEAT GEN_TAC THEN REWRITE_TAC[bounded] THEN
  EXISTS_TAC `norm(x:real^N) + e` THEN REWRITE_TAC[
IN_CBALL; dist] THEN
  NORM_ARITH_TAC);;
 
 
let FINITE_IMP_BOUNDED = prove
 (`!s:real^N->bool. 
FINITE s ==> bounded s`,
  MATCH_MP_TAC 
FINITE_INDUCT_STRONG THEN REWRITE_TAC[
BOUNDED_EMPTY] THEN
  REWRITE_TAC[bounded; 
IN_INSERT] THEN X_GEN_TAC `x:real^N` THEN GEN_TAC THEN
  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `B:real`) STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `norm(x:real^N) + abs B` THEN REPEAT STRIP_TAC THEN
  ASM_MESON_TAC[
NORM_POS_LE; REAL_ARITH
   `(y <= b /\ &0 <= x ==> y <= x + abs b) /\ x <= x + abs b`]);;
 
 
let BOUNDED_POS = prove
 (`!s. bounded s <=> ?b. &0 < b /\ !x. x 
IN s ==> norm(x) <= b`,
  REWRITE_TAC[bounded] THEN
  MESON_TAC[REAL_ARITH `&0 < &1 + abs(y) /\ (x <= y ==> x <= &1 + abs(y))`]);;
 
 
let BOUNDED_POS_LT = prove
 (`!s. bounded s <=> ?b. &0 < b /\ !x. x 
IN s ==> norm(x) < b`,
  REWRITE_TAC[bounded] THEN
  MESON_TAC[
REAL_LT_IMP_LE;
            REAL_ARITH `&0 < &1 + abs(y) /\ (x <= y ==> x < &1 + abs(y))`]);;
 
 
add_linear_invariants [BOUNDED_LINEAR_IMAGE_EQ];;
let BOUNDED_TRANSLATION = prove
 (`!a:real^N s. bounded s ==> bounded (
IMAGE (\x. a + x) s)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
BOUNDED_POS; 
FORALL_IN_IMAGE] THEN
  DISCH_THEN(X_CHOOSE_TAC `B:real`) THEN
  EXISTS_TAC `B + norm(a:real^N)` THEN POP_ASSUM MP_TAC THEN
  MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL [NORM_ARITH_TAC; ALL_TAC] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN
  REWRITE_TAC[] THEN NORM_ARITH_TAC);;
 
 
add_translation_invariants [BOUNDED_TRANSLATION_EQ];;
let BOUNDED_DIFFS = prove
 (`!s t:real^N->bool.
        bounded s /\ bounded t ==> bounded {x - y | x 
IN s /\ y 
IN t}`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
BOUNDED_POS] THEN
  DISCH_THEN(CONJUNCTS_THEN2
   (X_CHOOSE_TAC `B:real`) (X_CHOOSE_TAC `C:real`)) THEN
  EXISTS_TAC `B + C:real` THEN REWRITE_TAC[
IN_ELIM_THM] THEN
  CONJ_TAC THENL [ASM_REAL_ARITH_TAC; REPEAT STRIP_TAC] THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(NORM_ARITH
   `norm x <= a /\ norm y <= b ==> norm(x - y) <= a + b`) THEN
  ASM_SIMP_TAC[]);;
 
 
let BOUNDED_SUMS = prove
 (`!s t:real^N->bool.
        bounded s /\ bounded t ==> bounded {x + y | x 
IN s /\ y 
IN t}`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
BOUNDED_POS] THEN
  DISCH_THEN(CONJUNCTS_THEN2
   (X_CHOOSE_TAC `B:real`) (X_CHOOSE_TAC `C:real`)) THEN
  EXISTS_TAC `B + C:real` THEN REWRITE_TAC[
IN_ELIM_THM] THEN
  CONJ_TAC THENL [ASM_REAL_ARITH_TAC; REPEAT STRIP_TAC] THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(NORM_ARITH
   `norm x <= a /\ norm y <= b ==> norm(x + y) <= a + b`) THEN
  ASM_SIMP_TAC[]);;
 
 
let BOUNDED_SUBSET_BALL = prove
 (`!s x:real^N. bounded(s) ==> ?r. &0 < r /\ s 
SUBSET ball(x,r)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
BOUNDED_POS] THEN
  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `&2 * B + norm(x:real^N)` THEN
  ASM_SIMP_TAC[
NORM_POS_LE; REAL_ARITH
    `&0 < B /\ &0 <= x ==> &0 < &2 * B + x`] THEN
  REWRITE_TAC[
SUBSET] THEN X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`) THEN ASM_REWRITE_TAC[
IN_BALL] THEN
  UNDISCH_TAC `&0 < B` THEN NORM_ARITH_TAC);;
 
 
(* ------------------------------------------------------------------------- *)
(* Some theorems on sups and infs using the notion "bounded".                *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Subset and overlapping relations on balls.                                *)
(* ------------------------------------------------------------------------- *)
let SUBSET_BALLS = prove
 (`(!a a':real^N r r'.
      ball(a,r) 
SUBSET ball(a',r') <=> dist(a,a') + r <= r' \/ r <= &0) /\
   (!a a':real^N r r'.
      ball(a,r) 
SUBSET cball(a',r') <=> dist(a,a') + r <= r' \/ r <= &0) /\
   (!a a':real^N r r'.
      cball(a,r) 
SUBSET ball(a',r') <=> dist(a,a') + r < r' \/ r < &0) /\
   (!a a':real^N r r'.
      cball(a,r) 
SUBSET cball(a',r') <=> dist(a,a') + r <= r' \/ r < &0)`,
 
 
let INTER_BALLS_EQ_EMPTY = prove
 (`(!a b:real^N r s. ball(a,r) 
INTER ball(b,s) = {} <=>
                     r <= &0 \/ s <= &0 \/ r + s <= dist(a,b)) /\
   (!a b:real^N r s. ball(a,r) 
INTER cball(b,s) = {} <=>
                     r <= &0 \/ s < &0 \/ r + s <= dist(a,b)) /\
   (!a b:real^N r s. cball(a,r) 
INTER ball(b,s) = {} <=>
                     r < &0 \/ s <= &0 \/ r + s <= dist(a,b)) /\
   (!a b:real^N r s. cball(a,r) 
INTER cball(b,s) = {} <=>
                     r < &0 \/ s < &0 \/ r + s < dist(a,b))`,
 
 
(* ------------------------------------------------------------------------- *)
(* Every closed set is a G_Delta.                                            *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Compactness (the definition is the one based on convegent subsequences).  *)
(* ------------------------------------------------------------------------- *)
let compact = new_definition
  `compact s <=>
        !f:num->real^N.
            (!n. f(n) IN s)
            ==> ?l r. l IN s /\ (!m n:num. m < n ==> r(m) < r(n)) /\
                      ((f o r) --> l) sequentially`;; 
let MONOTONE_BIGGER = prove
 (`!r. (!m n. m < n ==> r(m) < r(n)) ==> !n:num. n <= r(n)`,
  GEN_TAC THEN DISCH_TAC THEN INDUCT_TAC THEN
  ASM_MESON_TAC[
LE_0; ARITH_RULE `n <= m /\ m < p ==> SUC n <= p`; 
LT]);;
 
 
let LIM_SUBSEQUENCE = prove
 (`!s r l. (!m n. m < n ==> r(m) < r(n)) /\ (s --> l) sequentially
           ==> (s o r --> l) sequentially`,
 
 
let MONOTONE_SUBSEQUENCE = prove
 (`!s:num->real. ?r:num->num.
           (!m n. m < n ==> r(m) < r(n)) /\
           ((!m n. m <= n ==> s(r(m)) <= s(r(n))) \/
            (!m n. m <= n ==> s(r(n)) <= s(r(m))))`,
  GEN_TAC THEN
  ASM_CASES_TAC `!n:num. ?p. n < p /\ !m. p <= m ==> s(m) <= s(p)` THEN
  POP_ASSUM MP_TAC THEN
  REWRITE_TAC[
NOT_FORALL_THM; 
NOT_EXISTS_THM; NOT_IMP; DE_MORGAN_THM] THEN
  REWRITE_TAC[
RIGHT_OR_EXISTS_THM; 
SKOLEM_THM; 
REAL_NOT_LE; 
REAL_NOT_LT] THENL
   [ABBREV_TAC `N = 0`; DISCH_THEN(X_CHOOSE_THEN `N:num` MP_TAC)] THEN
  DISCH_THEN(X_CHOOSE_THEN `next:num->num` STRIP_ASSUME_TAC) THEN
  (MP_TAC o prove_recursive_functions_exist num_RECURSION)
   `(r 0 = next(SUC N)) /\ (!n. r(SUC n) = next(r n))` THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN GEN_TAC THEN STRIP_TAC THENL
   [SUBGOAL_THEN `!m:num n:num. r n <= m ==> s(m) <= s(r n):real`
    ASSUME_TAC THEN TRY CONJ_TAC THEN TRY DISJ2_TAC THEN
    GEN_TAC THEN INDUCT_TAC THEN ASM_REWRITE_TAC[
LT; 
LE] THEN
    ASM_MESON_TAC[
REAL_LE_TRANS; 
REAL_LE_REFL; 
LT_IMP_LE; 
LT_TRANS];
    SUBGOAL_THEN `!n. N < (r:num->num) n` ASSUME_TAC THEN
    TRY(CONJ_TAC THENL [GEN_TAC; DISJ1_TAC THEN GEN_TAC]) THEN
    INDUCT_TAC THEN ASM_REWRITE_TAC[
LT; 
LE] THEN
    TRY STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
    ASM_MESON_TAC[
REAL_LT_REFL; 
LT_LE; 
LTE_TRANS; 
REAL_LE_REFL;
                  
REAL_LT_LE; 
REAL_LE_TRANS; 
LT]]);;
 
 
let CONVERGENT_BOUNDED_INCREASING = prove
 (`!s:num->real b. (!m n. m <= n ==> s m <= s n) /\ (!n. abs(s n) <= b)
                   ==> ?l. !e. &0 < e ==> ?N. !n. N <= n ==> abs(s n - l) < e`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPEC `\x. ?n. (s:num->real) n = x` 
REAL_COMPLETE) THEN
  REWRITE_TAC[] THEN ANTS_TAC THENL
   [ASM_MESON_TAC[REAL_ARITH `abs(x) <= b ==> x <= b`]; ALL_TAC] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `l:real` THEN STRIP_TAC THEN
  X_GEN_TAC `e:real` THEN STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `l - e`) THEN
  ASM_MESON_TAC[REAL_ARITH `&0 < e ==> ~(l <= l - e)`;
      REAL_ARITH `x <= y /\ y <= l /\ ~(x <= l - e) ==> abs(y - l) < e`]);;
 
 
let CONVERGENT_BOUNDED_MONOTONE = prove
 (`!s:num->real b. (!n. abs(s n) <= b) /\
                   ((!m n. m <= n ==> s m <= s n) \/
                    (!m n. m <= n ==> s n <= s m))
                   ==> ?l. !e. &0 < e ==> ?N. !n. N <= n ==> abs(s n - l) < e`,
 
 
let COMPACT_REAL_LEMMA = prove
 (`!s b. (!n:num. abs(s n) <= b)
         ==> ?l r. (!m n:num. m < n ==> r(m) < r(n)) /\
                   !e. &0 < e ==> ?N. !n. N <= n ==> abs(s(r n) - l) < e`,
 
 
let COMPACT_LEMMA = prove
 (`!s. bounded s /\ (!n. (x:num->real^N) n 
IN s)
       ==> !d. d <= dimindex(:N)
               ==> ?l:real^N r. (!m n. m < n ==> r m < (r:num->num) n) /\
                         !e. &0 < e
                             ==> ?N. !n i. 1 <= i /\ i <= d
                                           ==> N <= n
                                               ==> abs(x(r n)$i - l$i) < e`,
  GEN_TAC THEN REWRITE_TAC[bounded] THEN
  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `b:real`) ASSUME_TAC) THEN
  INDUCT_TAC THENL
   [REWRITE_TAC[ARITH_RULE `1 <= i /\ i <= 0 <=> F`; 
CONJ_ASSOC] THEN
    DISCH_TAC THEN EXISTS_TAC `\n:num. n` THEN REWRITE_TAC[];
    ALL_TAC] THEN
  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
  ASM_SIMP_TAC[ARITH_RULE `SUC d <= n ==> d <= n`] THEN STRIP_TAC THEN
  MP_TAC(SPECL [`\n:num. (x:num->real^N) (r n) $ (SUC d)`; `b:real`]
         
COMPACT_REAL_LEMMA) THEN
  REWRITE_TAC[] THEN ANTS_TAC THENL
   [ASM_MESON_TAC[
REAL_LE_TRANS; 
COMPONENT_LE_NORM; ARITH_RULE `1 <= SUC n`];
    ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `y:real` (X_CHOOSE_THEN `s:num->num`
        STRIP_ASSUME_TAC)) THEN
  MAP_EVERY EXISTS_TAC
   [`(lambda k. if k = SUC d then y else (l:real^N)$k):real^N`;
    `(r:num->num) o (s:num->num)`] THEN
  ASM_SIMP_TAC[
o_THM] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  REPEAT(FIRST_ASSUM(C UNDISCH_THEN (MP_TAC o SPEC `e:real`) o concl)) THEN
  ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_TAC `N1:num`) THEN
  DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN EXISTS_TAC `N1 + N2:num` THEN
  FIRST_ASSUM(fun th -> SIMP_TAC[
LAMBDA_BETA; MATCH_MP(ARITH_RULE
   `SUC d <= n ==> !i. 1 <= i /\ i <= SUC d ==> 1 <= i /\ i <= n`) th]) THEN
  REWRITE_TAC[
LE] THEN REPEAT STRIP_TAC THEN
  ASM_REWRITE_TAC[] THEN TRY COND_CASES_TAC THEN
  ASM_MESON_TAC[
MONOTONE_BIGGER; 
LE_TRANS;
    ARITH_RULE `N1 + N2 <= n ==> N2 <= n:num /\ N1 <= n`;
    ARITH_RULE `1 <= i /\ i <= d /\ SUC d <= n
                ==> ~(i = SUC d) /\ 1 <= SUC d /\ d <= n /\ i <= n`]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Completeness.                                                             *)
(* ------------------------------------------------------------------------- *)
let CAUCHY = prove
 (`!s:num->real^N.
      cauchy s <=> !e. &0 < e ==> ?N. !n. n >= N ==> dist(s n,s N) < e`,
  REPEAT GEN_TAC THEN REWRITE_TAC[cauchy; 
GE] THEN EQ_TAC THENL
   [MESON_TAC[
LE_REFL]; DISCH_TAC] THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[
REAL_HALF] THEN
  MESON_TAC[
DIST_TRIANGLE_HALF_L]);;
 
 
let COMPACT_IMP_COMPLETE = prove
 (`!s:real^N->bool. compact s ==> complete s`,
  GEN_TAC THEN REWRITE_TAC[complete; compact] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `f:num->real^N` THEN
  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
MONO_EXISTS THEN GEN_TAC THEN
  DISCH_THEN(X_CHOOSE_THEN `r:num->num` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[
IMP_CONJ] 
LIM_ADD)) THEN
  DISCH_THEN(MP_TAC o SPEC `\n. (f:num->real^N)(n) - f(r n)`) THEN
  DISCH_THEN(MP_TAC o SPEC `vec 0: real^N`) THEN ASM_REWRITE_TAC[
o_THM] THEN
  REWRITE_TAC[
VECTOR_ADD_RID; 
VECTOR_SUB_ADD2; ETA_AX] THEN
  DISCH_THEN MATCH_MP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [cauchy]) THEN
  REWRITE_TAC[
GE; 
LIM; 
SEQUENTIALLY; dist; 
VECTOR_SUB_RZERO] THEN
  SUBGOAL_THEN `!n:num. n <= r(n)` MP_TAC THENL [INDUCT_TAC; ALL_TAC] THEN
  ASM_MESON_TAC[ 
LE_TRANS; 
LE_REFL; 
LT; 
LET_TRANS; 
LE_0; 
LE_SUC_LT]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Total boundedness.                                                        *)
(* ------------------------------------------------------------------------- *)
let COMPACT_IMP_TOTALLY_BOUNDED = prove
 (`!s:real^N->bool.
        compact s
        ==> !e. &0 < e ==> ?k. 
FINITE k /\ k 
SUBSET s /\
                               s 
SUBSET (
UNIONS(
IMAGE (\x. ball(x,e)) k))`,
  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
  REWRITE_TAC[
NOT_FORALL_THM; NOT_IMP; 
NOT_EXISTS_THM] THEN
  REWRITE_TAC[TAUT `~(a /\ b /\ c) <=> a /\ b ==> ~c`; 
SUBSET] THEN
  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
  SUBGOAL_THEN
   `?x:num->real^N. !n. x(n) 
IN s /\ !m. m < n ==> ~(dist(x(m),x(n)) < e)`
  MP_TAC THENL
   [SUBGOAL_THEN
     `?x:num->real^N.
          !n. x(n) = @y. y 
IN s /\ !m. m < n ==> ~(dist(x(m),y) < e)`
    MP_TAC THENL
     [MATCH_MP_TAC(MATCH_MP 
WF_REC WF_num) THEN SIMP_TAC[]; ALL_TAC] THEN
    MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `x:num->real^N` THEN
    DISCH_TAC THEN MATCH_MP_TAC 
num_WF THEN X_GEN_TAC `n:num` THEN
    FIRST_X_ASSUM(SUBST1_TAC o SPEC `n:num`) THEN STRIP_TAC THEN
    CONV_TAC SELECT_CONV THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `
IMAGE (x:num->real^N) {m | m < n}`) THEN
    SIMP_TAC[
FINITE_IMAGE; 
FINITE_NUMSEG_LT; 
NOT_FORALL_THM; NOT_IMP] THEN
    REWRITE_TAC[
IN_UNIONS; 
IN_IMAGE; 
IN_ELIM_THM] THEN ASM_MESON_TAC[
IN_BALL];
    ALL_TAC] THEN
  REWRITE_TAC[compact; 
NOT_FORALL_THM] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
  X_GEN_TAC `x:num->real^N` THEN  REWRITE_TAC[NOT_IMP; 
FORALL_AND_THM] THEN
  STRIP_TAC THEN ASM_REWRITE_TAC[
NOT_EXISTS_THM] THEN REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o MATCH_MP 
CONVERGENT_IMP_CAUCHY) THEN
  REWRITE_TAC[cauchy] THEN DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
  ASM_REWRITE_TAC[
o_THM; 
NOT_EXISTS_THM; NOT_IMP; 
NOT_FORALL_THM; NOT_IMP] THEN
  X_GEN_TAC `N:num` THEN MAP_EVERY EXISTS_TAC [`N:num`; `SUC N`] THEN
  CONJ_TAC THENL [ARITH_TAC; ASM_MESON_TAC[
LT]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Heine-Borel theorem (following Burkill & Burkill vol. 2)                  *)
(* ------------------------------------------------------------------------- *)
let HEINE_BOREL_LEMMA = prove
 (`!s:real^N->bool.
      compact s
      ==> !t. s 
SUBSET (
UNIONS t) /\ (!b. b 
IN t ==> open b)
              ==> ?e. &0 < e /\
                      !x. x 
IN s ==> ?b. b 
IN t /\ ball(x,e) 
SUBSET b`,
  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
  REWRITE_TAC[
NOT_FORALL_THM; NOT_IMP; 
NOT_EXISTS_THM] THEN
  DISCH_THEN(CHOOSE_THEN (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  DISCH_THEN(MP_TAC o GEN `n:num` o SPEC `&1 / (&n + &1)`) THEN
  SIMP_TAC[
REAL_LT_DIV; 
REAL_LT_01; REAL_ARITH `x <= y ==> x < y + &1`;
   
FORALL_AND_THM; 
REAL_POS; 
NOT_FORALL_THM; NOT_IMP; 
SKOLEM_THM; compact] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN GEN_TAC THEN REWRITE_TAC[
NOT_EXISTS_THM] THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
  DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`l:real^N`; `r:num->num`] THEN
  STRIP_TAC THEN
  SUBGOAL_THEN `?b:real^N->bool. l 
IN b /\ b 
IN t` STRIP_ASSUME_TAC THENL
   [ASM_MESON_TAC[
SUBSET; 
IN_UNIONS]; ALL_TAC] THEN
  SUBGOAL_THEN `?e. &0 < e /\ !z:real^N. dist(z,l) < e ==> z 
IN b`
  STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[
open_def]; ALL_TAC] THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
LIM_SEQUENTIALLY]) THEN
  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
  SUBGOAL_THEN `&0 < e / &2` (fun th ->
    REWRITE_TAC[th; 
o_THM] THEN MP_TAC(GEN_REWRITE_RULE I [
REAL_ARCH_INV] th))
  THENL [ASM_REWRITE_TAC[
REAL_HALF]; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `N1:num` STRIP_ASSUME_TAC) THEN
  DISCH_THEN(X_CHOOSE_THEN `N2:num` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPECL
   [`(r:num->num)(N1 + N2)`; `b:real^N->bool`]) THEN
  ASM_REWRITE_TAC[
SUBSET] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
  FIRST_X_ASSUM MATCH_MP_TAC THEN MATCH_MP_TAC 
DIST_TRIANGLE_HALF_R THEN
  EXISTS_TAC `(f:num->real^N)(r(N1 + N2:num))` THEN CONJ_TAC THENL
   [ALL_TAC; FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC] THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
IN_BALL]) THEN
  MATCH_MP_TAC(REAL_ARITH `a <= b ==> x < a ==> x < b`) THEN
  MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `inv(&N1)` THEN
  ASM_SIMP_TAC[
REAL_LT_IMP_LE] THEN REWRITE_TAC[
real_div; REAL_MUL_LID] THEN
  MATCH_MP_TAC 
REAL_LE_INV2 THEN
  REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; 
REAL_OF_NUM_LT] THEN
  ASM_MESON_TAC[ARITH_RULE `(~(n = 0) ==> 0 < n)`; 
LE_ADD; 
MONOTONE_BIGGER;
                
LT_IMP_LE; 
LE_TRANS]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Bolzano-Weierstrass property.                                             *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Complete the chain of compactness variants.                               *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Hence express everything as an equivalence.                               *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* A version of Heine-Borel for subtopology.                                 *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* More easy lemmas.                                                         *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* In particular, some common special cases.                                 *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Finite intersection property. I could make it an equivalence in fact.     *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Bounded closed nest property (proof does not use Heine-Borel).            *)
(* ------------------------------------------------------------------------- *)
let BOUNDED_CLOSED_NEST = prove
 (`!s. (!n. closed(s n)) /\ (!n. ~(s n = {})) /\
       (!m n. m <= n ==> s(n) 
SUBSET s(m)) /\
       bounded(s 0)
       ==> ?a:real^N. !n:num. a 
IN s(n)`,
  GEN_TAC THEN REWRITE_TAC[GSYM 
MEMBER_NOT_EMPTY; 
SKOLEM_THM] THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  DISCH_THEN(CONJUNCTS_THEN2
     (X_CHOOSE_TAC `a:num->real^N`) STRIP_ASSUME_TAC) THEN
  SUBGOAL_THEN `compact(s 0:real^N->bool)` MP_TAC THENL
   [ASM_MESON_TAC[
BOUNDED_CLOSED_IMP_COMPACT]; ALL_TAC] THEN
  REWRITE_TAC[compact] THEN
  DISCH_THEN(MP_TAC o SPEC `a:num->real^N`) THEN
  ANTS_TAC THENL [ASM_MESON_TAC[
SUBSET; 
LE_0]; ALL_TAC] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `l:real^N` THEN
  REWRITE_TAC[
LIM_SEQUENTIALLY; 
o_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `r:num->num` STRIP_ASSUME_TAC) THEN
  GEN_REWRITE_TAC I [TAUT `p <=> ~(~p)`] THEN
  GEN_REWRITE_TAC RAND_CONV [
NOT_FORALL_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `N:num` MP_TAC) THEN
  MP_TAC(ISPECL [`l:real^N`; `(s:num->real^N->bool) N`]
                
CLOSED_APPROACHABLE) THEN
  ASM_MESON_TAC[
SUBSET; 
LE_REFL; 
LE_TRANS; 
LE_CASES; 
MONOTONE_BIGGER]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Decreasing case does not even need compactness, just completeness.        *)
(* ------------------------------------------------------------------------- *)
let DECREASING_CLOSED_NEST = prove
 (`!s. (!n. closed(s n)) /\ (!n. ~(s n = {})) /\
       (!m n. m <= n ==> s(n) 
SUBSET s(m)) /\
       (!e. &0 < e ==> ?n. !x y. x 
IN s(n) /\ y 
IN s(n) ==> dist(x,y) < e)
       ==> ?a:real^N. !n:num. a 
IN s(n)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Strengthen it to the intersection actually being a singleton.             *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* A version for a more general chain, not indexed by N.                     *)
(* ------------------------------------------------------------------------- *)
let BOUNDED_CLOSED_CHAIN = prove
 (`!f b:real^N->bool.
        (!s. s 
IN f ==> closed s /\ ~(s = {})) /\
        (!s t. s 
IN f /\ t 
IN f ==> s 
SUBSET t \/ t 
SUBSET s) /\
         b 
IN f /\ bounded b
         ==> ~(
INTERS f = {})`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN
  SUBGOAL_THEN `~(b 
INTER (
INTERS f):real^N->bool = {})` MP_TAC THENL
   [ALL_TAC; SET_TAC[]] THEN
  MATCH_MP_TAC 
COMPACT_IMP_FIP THEN
  ASM_SIMP_TAC[
COMPACT_EQ_BOUNDED_CLOSED] THEN
  X_GEN_TAC `u:(real^N->bool)->bool` THEN STRIP_TAC THEN
  SUBGOAL_THEN `?s:real^N->bool. s 
IN f /\ !t. t 
IN u ==> s 
SUBSET t`
  MP_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
  UNDISCH_TAC `(u:(real^N->bool)->bool) 
SUBSET f` THEN
  UNDISCH_TAC `
FINITE(u:(real^N->bool)->bool)` THEN
  SPEC_TAC(`u:(real^N->bool)->bool`,`u:(real^N->bool)->bool`) THEN
  MATCH_MP_TAC 
FINITE_INDUCT_STRONG THEN
  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
  MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `u:(real^N->bool)->bool`] THEN
  REWRITE_TAC[
INSERT_SUBSET] THEN
  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
  DISCH_THEN(X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`s:real^N->bool`; `t:real^N->bool`]) THEN
  ASM SET_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Analogous things directly for compactness.                                *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Cauchy-type criteria for *uniform* convergence.                           *)
(* ------------------------------------------------------------------------- *)
let UNIFORMLY_CONVERGENT_EQ_CAUCHY = prove
 (`!P s:num->A->real^N.
         (?l. !e. &0 < e
                  ==> ?N. !n x. N <= n /\ P x ==> dist(s n x,l x) < e) <=>
         (!e. &0 < e
              ==> ?N. !m n x. N <= m /\ N <= n /\ P x
                              ==> dist(s m x,s n x) < e)`,
  REPEAT GEN_TAC THEN EQ_TAC THENL
   [DISCH_THEN(X_CHOOSE_TAC `l:A->real^N`) THEN X_GEN_TAC `e:real` THEN
    DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
    ASM_REWRITE_TAC[
REAL_HALF] THEN MESON_TAC[
DIST_TRIANGLE_HALF_L];
    ALL_TAC] THEN
  DISCH_TAC THEN
  SUBGOAL_THEN `!x:A. P x ==> cauchy (\n. s n x :real^N)` MP_TAC THENL
   [REWRITE_TAC[cauchy; 
GE] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
  REWRITE_TAC[GSYM 
CONVERGENT_EQ_CAUCHY; 
LIM_SEQUENTIALLY] THEN
  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [
RIGHT_IMP_EXISTS_THM] THEN
  REWRITE_TAC[
SKOLEM_THM] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
  X_GEN_TAC `l:A->real^N` THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN
  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  ASM_REWRITE_TAC[
REAL_HALF] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
  X_GEN_TAC `N:num` THEN STRIP_TAC THEN
  MAP_EVERY X_GEN_TAC [`n:num`; `x:A`] THEN STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `x:A`) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[
REAL_HALF] THEN
  DISCH_THEN(X_CHOOSE_TAC `M:num`) THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`n:num`; `N + M:num`; `x:A`]) THEN
  ASM_REWRITE_TAC[
LE_ADD] THEN ONCE_REWRITE_TAC[
ADD_SYM] THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `M + N:num`) THEN REWRITE_TAC[
LE_ADD] THEN
  ASM_MESON_TAC[
DIST_TRIANGLE_HALF_L; 
DIST_SYM]);;
 
 
let UNIFORMLY_CAUCHY_IMP_UNIFORMLY_CONVERGENT = prove
 (`!P (s:num->A->real^N) l.
    (!e. &0 < e
         ==> ?N. !m n x. N <= m /\ N <= n /\ P x ==> dist(s m x,s n x) < e) /\
    (!x. P x ==> !e. &0 < e ==> ?N. !n. N <= n ==> dist(s n x,l x) < e)
    ==> (!e. &0 < e ==> ?N. !n x. N <= n /\ P x ==> dist(s n x,l x) < e)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM 
UNIFORMLY_CONVERGENT_EQ_CAUCHY] THEN
  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `l':A->real^N`) ASSUME_TAC) THEN
  SUBGOAL_THEN `!x. P x ==> (l:A->real^N) x = l' x` MP_TAC THENL
   [ALL_TAC; ASM_MESON_TAC[]] THEN
  REPEAT STRIP_TAC THEN MATCH_MP_TAC(ISPEC `sequentially` 
LIM_UNIQUE) THEN
  EXISTS_TAC `\n. (s:num->A->real^N) n x` THEN
  REWRITE_TAC[
LIM_SEQUENTIALLY; 
TRIVIAL_LIMIT_SEQUENTIALLY] THEN
  ASM_MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Define continuity over a net to take in restrictions of the set.          *)
(* ------------------------------------------------------------------------- *)
parse_as_infix ("continuous",(12,"right"));;
let CONTINUOUS_TRANSFORM_WITHIN = prove
 (`!f g:real^M->real^N s x d.
        &0 < d /\ x 
IN s /\
        (!x'. x' 
IN s /\ dist(x',x) < d ==> f(x') = g(x')) /\
        f continuous (at x within s)
        ==> g continuous (at x within s)`,
 
 
let CONTINUOUS_TRANSFORM_AT = prove
 (`!f g:real^M->real^N x d.
        &0 < d /\ (!x'. dist(x',x) < d ==> f(x') = g(x')) /\
        f continuous (at x)
        ==> g continuous (at x)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Derive the epsilon-delta forms, which we often use as "definitions"       *)
(* ------------------------------------------------------------------------- *)
let continuous_within = prove
 (`f continuous (at x within s) <=>
        !e. &0 < e
            ==> ?d. &0 < d /\
                    !x'. x' 
IN s /\ dist(x',x) < d ==> dist(f(x'),f(x)) < e`,
 
 
let continuous_at = prove
 (`f continuous (at x) <=>
        !e. &0 < e ==> ?d. &0 < d /\
                           !x'. dist(x',x) < d ==> dist(f(x'),f(x)) < e`,
 
 
(* ------------------------------------------------------------------------- *)
(* Versions in terms of open balls.                                          *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* For setwise continuity, just start from the epsilon-delta definitions.    *)
(* ------------------------------------------------------------------------- *)
parse_as_infix ("continuous_on",(12,"right"));;
parse_as_infix ("uniformly_continuous_on",(12,"right"));;
(* ------------------------------------------------------------------------- *)
(* Some simple consequential lemmas.                                         *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Characterization of various kinds of continuity in terms of sequences.    *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Combination results for pointwise continuity.                             *)
(* ------------------------------------------------------------------------- *)
let CONTINUOUS_ADD = prove
 (`!f g net. f continuous net /\ g continuous net
           ==> (\x. f(x) + g(x)) continuous net`,
  REWRITE_TAC[continuous; 
LIM_ADD]);;
 
 
let CONTINUOUS_SUB = prove
 (`!f g net. f continuous net /\ g continuous net
           ==> (\x. f(x) - g(x)) continuous net`,
  REWRITE_TAC[continuous; 
LIM_SUB]);;
 
 
let CONTINUOUS_ABS = prove
 (`!(f:A->real^N) net.
        f continuous net
        ==> (\x. (lambda i. abs(f(x)$i)):real^N) continuous net`,
  REWRITE_TAC[continuous; 
LIM_ABS]);;
 
 
let CONTINUOUS_MAX = prove
 (`!(f:A->real^N) (g:A->real^N) net.
        f continuous net /\ g continuous net
        ==> (\x. (lambda i. max (f(x)$i) (g(x)$i)):real^N) continuous net`,
  REWRITE_TAC[continuous; 
LIM_MAX]);;
 
 
let CONTINUOUS_MIN = prove
 (`!(f:A->real^N) (g:A->real^N) net.
        f continuous net /\ g continuous net
        ==> (\x. (lambda i. min (f(x)$i) (g(x)$i)):real^N) continuous net`,
  REWRITE_TAC[continuous; 
LIM_MIN]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Same thing for setwise continuity.                                        *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Same thing for uniform continuity, using sequential formulations.         *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Identity function is continuous in every sense.                           *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Continuity of all kinds is preserved under composition.                   *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Continuity in terms of open preimages.                                    *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Similarly in terms of closed sets.                                        *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Half-global and completely global cases.                                  *)
(* ------------------------------------------------------------------------- *)
let CONTINUOUS_OPEN_PREIMAGE = prove
 (`!f:real^M->real^N s t.
     f 
continuous_on s /\ open s /\ open t
     ==> open {x | x 
IN s /\ f(x) 
IN t}`,
  REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
CONTINUOUS_ON_OPEN]) THEN
  REWRITE_TAC [
OPEN_IN_OPEN] THEN
  DISCH_THEN(MP_TAC o SPEC `
IMAGE (f:real^M->real^N) s 
INTER t`) THEN
  ANTS_TAC THENL
   [EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC [];
    STRIP_TAC THEN
    SUBGOAL_THEN `{x | x 
IN s /\ (f:real^M->real^N) x 
IN t} =
                 s 
INTER t'` SUBST1_TAC THENL
    [ASM SET_TAC []; ASM_MESON_TAC [
OPEN_INTER]]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Linear functions are (uniformly) continuous on any set.                   *)
(* ------------------------------------------------------------------------- *)
let LINEAR_CONTINUOUS_AT = prove
 (`!f:real^M->real^N a. linear f ==> f continuous (at a)`,
  REPEAT STRIP_TAC THEN
  MP_TAC(ISPEC `\x. (f:real^M->real^N) (a + x) - f(a)` 
LINEAR_LIM_0) THEN
  ANTS_TAC THENL
   [POP_ASSUM MP_TAC THEN SIMP_TAC[linear] THEN
    REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC;
    ALL_TAC] THEN
  REWRITE_TAC[GSYM 
LIM_NULL; 
CONTINUOUS_AT] THEN
  GEN_REWRITE_TAC RAND_CONV [
LIM_AT_ZERO] THEN SIMP_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Also bilinear functions, in composition form.                             *)
(* ------------------------------------------------------------------------- *)
let BILINEAR_CONTINUOUS_COMPOSE = prove
 (`!net f:A->real^M g:A->real^N h:real^M->real^N->real^P.
        f continuous net /\ g continuous net /\ bilinear h
        ==> (\x. h (f x) (g x)) continuous net`,
 
 
(* ------------------------------------------------------------------------- *)
(* Preservation of compactness and connectedness under continuous function.  *)
(* ------------------------------------------------------------------------- *)
let COMPACT_CONTINUOUS_IMAGE = prove
 (`!f:real^M->real^N s.
        f 
continuous_on s /\ compact s ==> compact(
IMAGE f s)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
continuous_on; compact] THEN
  STRIP_TAC THEN X_GEN_TAC `y:num->real^N` THEN
  REWRITE_TAC[
IN_IMAGE; 
SKOLEM_THM; 
FORALL_AND_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `x:num->real^M` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `x:num->real^M`) THEN ASM_REWRITE_TAC[] THEN
  ONCE_REWRITE_TAC[
SWAP_EXISTS_THM] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
  X_GEN_TAC `r:num->num` THEN
  DISCH_THEN(X_CHOOSE_THEN `l:real^M` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `(f:real^M->real^N) l` THEN ASM_REWRITE_TAC[] THEN
  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
  REWRITE_TAC[
LIM_SEQUENTIALLY] THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `l:real^M`) THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `e:real` THEN
  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
LIM_SEQUENTIALLY]) THEN
  DISCH_THEN(MP_TAC o SPEC `d:real`) THEN ASM_REWRITE_TAC[
o_THM] THEN
  ASM_MESON_TAC[]);;
 
 
add_translation_invariants [COMPACT_TRANSLATION_EQ];;
add_linear_invariants [COMPACT_LINEAR_IMAGE_EQ];;
add_translation_invariants [CONNECTED_TRANSLATION_EQ];;
add_linear_invariants [CONNECTED_LINEAR_IMAGE_EQ];;
(* ------------------------------------------------------------------------- *)
(* Preservation properties for pasted sets (Cartesian products).             *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Quotient maps are occasionally useful.                                    *)
(* ------------------------------------------------------------------------- *)
let CONTINUOUS_ON_COMPOSE_QUOTIENT = prove
 (`!f:real^M->real^N g:real^N->real^P s t u.
      
IMAGE f s 
SUBSET t /\ 
IMAGE g t 
SUBSET u /\
      (!v. v 
SUBSET t
           ==> (
open_in (subtopology euclidean s) {x | x 
IN s /\ f x 
IN v} <=>
                
open_in (subtopology euclidean t) v)) /\
      (g o f) 
continuous_on s
      ==> g 
continuous_on t`,
  REPEAT GEN_TAC THEN
  REPLICATE_TAC 3 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP 
CONTINUOUS_ON_OPEN_GEN th]) THEN
  SUBGOAL_THEN
   `
IMAGE ((g:real^N->real^P) o (f:real^M->real^N)) s 
SUBSET u`
   (fun th -> REWRITE_TAC[MATCH_MP 
CONTINUOUS_ON_OPEN_GEN th])
  THENL [REWRITE_TAC[
IMAGE_o] THEN ASM SET_TAC[]; DISCH_TAC] THEN
  X_GEN_TAC `v:real^P->bool` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `v:real^P->bool`) THEN
  ASM_REWRITE_TAC[
o_THM] THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `{x | x 
IN t /\ (g:real^N->real^P) x 
IN v}`) THEN
  ASM_REWRITE_TAC[
SUBSET_RESTRICT] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
   `
open_in top s ==> s = t ==> 
open_in top t`)) THEN
  ASM SET_TAC[]);;
 
 
let QUOTIENT_MAP_COMPOSE = prove
 (`!f:real^M->real^N g:real^N->real^P s t u.
        
IMAGE f s 
SUBSET t /\
        (!v. v 
SUBSET t
           ==> (
open_in (subtopology euclidean s) {x | x 
IN s /\ f x 
IN v} <=>
                
open_in (subtopology euclidean t) v)) /\
        (!v. v 
SUBSET u
           ==> (
open_in (subtopology euclidean t) {x | x 
IN t /\ g x 
IN v} <=>
                
open_in (subtopology euclidean u) v))
        ==> !v. v 
SUBSET u
                ==> (
open_in (subtopology euclidean s)
                             {x | x 
IN s /\ (g o f) x 
IN v} <=>
                     
open_in (subtopology euclidean u) v)`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[
o_THM] THEN
  SUBGOAL_THEN
   `{x | x 
IN s /\ (g:real^N->real^P) ((f:real^M->real^N) x) 
IN v} =
    {x | x 
IN s /\ f x 
IN {x | x 
IN t /\ g x 
IN v}}`
  SUBST1_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[
SUBSET_RESTRICT]]);;
 
 
let CONNECTED_MONOTONE_QUOTIENT_PREIMAGE = prove
 (`!f:real^M->real^N s t.
      f 
continuous_on s /\ 
IMAGE f s = t /\
      (!u. u 
SUBSET t
           ==> (
open_in (subtopology euclidean s) {x | x 
IN s /\ f x 
IN u} <=>
                
open_in (subtopology euclidean t) u)) /\
      (!y. y 
IN t ==> connected {x | x 
IN s /\ f x = y}) /\
      connected t
      ==> connected s`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[connected; 
NOT_EXISTS_THM] THEN
  MAP_EVERY X_GEN_TAC [`u:real^M->bool`; `v:real^M->bool`] THEN STRIP_TAC THEN
  UNDISCH_TAC `connected(t:real^N->bool)` THEN SIMP_TAC[
CONNECTED_OPEN_IN] THEN
  MAP_EVERY EXISTS_TAC
   [`
IMAGE (f:real^M->real^N) (s 
INTER u)`;
    `
IMAGE (f:real^M->real^N) (s 
INTER v)`] THEN
  ASM_REWRITE_TAC[
IMAGE_EQ_EMPTY] THEN
  SUBGOAL_THEN
   `
IMAGE (f:real^M->real^N) (s 
INTER u) 
INTER IMAGE f (s 
INTER v) = {}`
  ASSUME_TAC THENL
   [REWRITE_TAC[
EXTENSION; 
IN_INTER; 
NOT_IN_EMPTY] THEN
    X_GEN_TAC `y:real^N` THEN STRIP_TAC  THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`) THEN
    ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[connected]] THEN
    MAP_EVERY EXISTS_TAC [`u:real^M->bool`; `v:real^M->bool`] THEN
    ASM SET_TAC[];
    ALL_TAC] THEN
  ONCE_REWRITE_TAC[
CONJ_ASSOC] THEN
  CONJ_TAC THENL [CONJ_TAC; ASM SET_TAC[]] THEN
  FIRST_X_ASSUM(fun th ->
   W(MP_TAC o PART_MATCH (rand o rand) th o snd)) THEN
  (ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN(SUBST1_TAC o SYM)]) THEN
  MATCH_MP_TAC(MESON[]
   `{x | x 
IN s /\ f x 
IN IMAGE f u} = u /\ 
open_in top u
    ==> 
open_in top {x | x 
IN s /\ f x 
IN IMAGE f u}`) THEN
  ASM_SIMP_TAC[
OPEN_IN_OPEN_INTER] THEN ASM SET_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* More properties of open and closed maps.                                  *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Proper maps, including projections out of compact sets.                   *)
(* ------------------------------------------------------------------------- *)
let PROPER_MAP_COMPOSE = prove
 (`!f:real^M->real^N g:real^N->real^P s t u.
        
IMAGE f s 
SUBSET t /\
        (!k. k 
SUBSET t /\ compact k ==> compact {x | x 
IN s /\ f x 
IN k}) /\
        (!k. k 
SUBSET u /\ compact k ==> compact {x | x 
IN t /\ g x 
IN k})
        ==> !k. k 
SUBSET u /\ compact k
                ==> compact {x | x 
IN s /\ (g o f) x 
IN k}`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[
o_THM] THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `k:real^P->bool`) THEN
  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `{x | x 
IN t /\ (g:real^N->real^P) x 
IN k}`) THEN
  ANTS_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC EQ_IMP] THEN
  AP_TERM_TAC THEN ASM SET_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Pasting functions together on open sets.                                  *)
(* ------------------------------------------------------------------------- *)
let PASTING_LEMMA_EXISTS = prove
 (`!f:A->real^M->real^N t s k.
        s 
SUBSET UNIONS {t i | i 
IN k} /\
        (!i. i 
IN k
             ==> 
open_in (subtopology euclidean s) (t i) /\
                 (f i) 
continuous_on (t i)) /\
        (!i j x. i 
IN k /\ j 
IN k /\ x 
IN s 
INTER t i 
INTER t j
                 ==> f i x = f j x)
        ==> ?g. g 
continuous_on s /\
                (!x i. i 
IN k /\ x 
IN s 
INTER t i ==> g x = f i x)`,
  REPEAT STRIP_TAC THEN
  EXISTS_TAC `\x. (f:A->real^M->real^N)(@i. i 
IN k /\ x 
IN t i) x` THEN
  CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN MATCH_MP_TAC 
PASTING_LEMMA THEN
  MAP_EVERY EXISTS_TAC
   [`f:A->real^M->real^N`; `t:A->real^M->bool`; `k:A->bool`] THEN
  ASM SET_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Likewise on closed sets, with a finiteness assumption.                    *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Closure of halflines, halfspaces and hyperplanes.                         *)
(* ------------------------------------------------------------------------- *)
let LIM_LIFT_DOT = prove
 (`!f:real^M->real^N a.
        (f --> l) net ==> ((lift o (\y. a dot f(y))) --> lift(a dot l)) net`,
 
 
(* ------------------------------------------------------------------------- *)
(* Openness of halfspaces.                                                   *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Closures and interiors of halfspaces.                                     *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Unboundedness of halfspaces.                                              *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Equality of continuous functions on closure and related results.          *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Theorems relating continuity and uniform continuity to closures.          *)
(* ------------------------------------------------------------------------- *)
let CONTINUOUS_ON_CLOSURE = prove
 (`!f:real^M->real^N s.
        f 
continuous_on closure s <=>
        !x e. x 
IN closure s /\ &0 < e
              ==> ?d. &0 < d /\
                      !y. y 
IN s /\ dist(y,x) < d ==> dist(f y,f x) < e`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
continuous_on] THEN
  EQ_TAC THENL [MESON_TAC[REWRITE_RULE[
SUBSET] 
CLOSURE_SUBSET]; ALL_TAC] THEN
  DISCH_TAC THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_ASSUM(MP_TAC o SPECL [`x:real^M`; `e / &2`]) THEN
  ANTS_TAC THENL [ASM_REWRITE_TAC[
REAL_HALF]; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `d / &2` THEN ASM_REWRITE_TAC[
REAL_HALF] THEN
  X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`y:real^M`; `e / &2`]) THEN
  ASM_REWRITE_TAC[
REAL_HALF] THEN
  DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
  MP_TAC(ISPECL [`y:real^M`; `s:real^M->bool`] 
CLOSURE_APPROACHABLE) THEN
  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `min k (d / &2)`) THEN
  ASM_REWRITE_TAC[
REAL_HALF; 
REAL_LT_MIN] THEN
  ASM_MESON_TAC[
DIST_SYM; NORM_ARITH
    `dist(a,b) < e / &2 /\ dist(b,c) < e / &2 ==> dist(a,c) < e`]);;
 
 
let UNIFORMLY_CONTINUOUS_ON_CLOSURE = prove
 (`!f:real^M->real^N s.
        f 
uniformly_continuous_on s /\ f 
continuous_on closure s
        ==> f 
uniformly_continuous_on closure s`,
  REPEAT GEN_TAC THEN
  REWRITE_TAC[
uniformly_continuous_on] THEN STRIP_TAC THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &3`) THEN
  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `d / &3` THEN CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
  MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^M`] THEN STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
continuous_on]) THEN
  DISCH_THEN(fun th ->
    MP_TAC(SPEC `y:real^M` th) THEN MP_TAC(SPEC `x:real^M` th)) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `d1:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  MP_TAC(ISPECL [`x:real^M`; `s:real^M->bool`] 
CLOSURE_APPROACHABLE) THEN
  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `min d1 (d / &3)`) THEN
  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[
REAL_LT_MIN]] THEN
  DISCH_THEN(X_CHOOSE_THEN `x':real^M` STRIP_ASSUME_TAC) THEN
  DISCH_THEN(MP_TAC o SPEC `x':real^M`) THEN
  ASM_SIMP_TAC[REWRITE_RULE[
SUBSET] 
CLOSURE_SUBSET] THEN DISCH_TAC THEN
  DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `d2:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  MP_TAC(ISPECL [`y:real^M`; `s:real^M->bool`] 
CLOSURE_APPROACHABLE) THEN
  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `min d2 (d / &3)`) THEN
  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[
REAL_LT_MIN]] THEN
  DISCH_THEN(X_CHOOSE_THEN `y':real^M` STRIP_ASSUME_TAC) THEN
  DISCH_THEN(MP_TAC o SPEC `y':real^M`) THEN
  ASM_SIMP_TAC[REWRITE_RULE[
SUBSET] 
CLOSURE_SUBSET] THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`x':real^M`; `y':real^M`]) THEN
  ASM_MESON_TAC[
DIST_SYM; NORM_ARITH
   `dist(y,x) < d / &3 /\ dist(x',x) < d / &3 /\ dist(y',y) < d / &3
    ==> dist(y',x') < d`]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Continuity properties for square roots. We get other forms of this        *)
(* later (transcendentals.ml and realanalysis.ml) but it's nice to have      *)
(* them around earlier.                                                      *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Cauchy continuity, and the extension of functions to closures.            *)
(* ------------------------------------------------------------------------- *)
let CAUCHY_CONTINUOUS_UNIQUENESS_LEMMA = prove
 (`!f:real^M->real^N s.
        (!x. cauchy x /\ (!n. (x n) 
IN s) ==> cauchy(f o x))
        ==> !a x. (!n. (x n) 
IN s) /\ (x --> a) sequentially
                  ==> ?l. ((f o x) --> l) sequentially /\
                          !y. (!n. (y n) 
IN s) /\ (y --> a) sequentially
                              ==> ((f o y) --> l) sequentially`,
  REPEAT STRIP_TAC THEN
  FIRST_ASSUM(MP_TAC o SPEC `x:num->real^M`) THEN
  ANTS_TAC THENL [ASM_MESON_TAC[
CONVERGENT_IMP_CAUCHY]; ALL_TAC] THEN
  REWRITE_TAC[GSYM 
CONVERGENT_EQ_CAUCHY] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
  X_GEN_TAC `l:real^N` THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
  X_GEN_TAC `y:num->real^M` THEN STRIP_TAC THEN
  FIRST_ASSUM(MP_TAC o SPEC `y:num->real^M`) THEN
  ANTS_TAC THENL [ASM_MESON_TAC[
CONVERGENT_IMP_CAUCHY]; ALL_TAC] THEN
  REWRITE_TAC[GSYM 
CONVERGENT_EQ_CAUCHY] THEN
  DISCH_THEN(X_CHOOSE_THEN `m:real^N` STRIP_ASSUME_TAC) THEN
  SUBGOAL_THEN `l:real^N = m` (fun th -> ASM_REWRITE_TAC[th]) THEN
  ONCE_REWRITE_TAC[GSYM 
VECTOR_SUB_EQ] THEN
  MATCH_MP_TAC(ISPEC `sequentially` 
LIM_UNIQUE) THEN
  EXISTS_TAC `\n:num. (f:real^M->real^N)(x n) - f(y n)` THEN
  RULE_ASSUM_TAC(REWRITE_RULE[
o_DEF]) THEN
  ASM_SIMP_TAC[
LIM_SUB; 
TRIVIAL_LIMIT_SEQUENTIALLY] THEN
  FIRST_X_ASSUM(MP_TAC o SPEC
   `\n. if 
EVEN n then x(n DIV 2):real^M else y(n DIV 2)`) THEN
  REWRITE_TAC[cauchy; 
o_THM; 
LIM_SEQUENTIALLY] THEN ANTS_TAC THENL
   [CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
    X_GEN_TAC `e:real` THEN DISCH_TAC THEN MAP_EVERY UNDISCH_TAC
     [`((y:num->real^M) --> a) sequentially`;
      `((x:num->real^M) --> a) sequentially`] THEN
    REPEAT(FIRST_X_ASSUM(K ALL_TAC o check (is_forall o concl))) THEN
    REWRITE_TAC[
LIM_SEQUENTIALLY] THEN
    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[
REAL_HALF] THEN
    DISCH_THEN(X_CHOOSE_TAC `N1:num`) THEN
    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[
REAL_HALF] THEN
    DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN
    EXISTS_TAC `2 * (N1 + N2)` THEN
    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN STRIP_TAC THEN
    REPEAT(FIRST_X_ASSUM(fun th ->
      MP_TAC(SPEC `m DIV 2` th) THEN MP_TAC(SPEC `n DIV 2` th))) THEN
    REPEAT(ANTS_TAC THENL [ASM_ARITH_TAC; DISCH_TAC]) THEN
    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM 
REAL_NOT_LE])) THEN
    CONV_TAC NORM_ARITH;
    MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `e:real` THEN
    ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
    MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `N:num` THEN DISCH_TAC THEN
    X_GEN_TAC `n:num` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPECL [`2 * n`; `2 * n + 1`]) THEN
    ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
    REWRITE_TAC[
EVEN_ADD; 
EVEN_MULT; 
ARITH_EVEN] THEN
    REWRITE_TAC[ARITH_RULE `(2 * n) DIV 2 = n /\ (2 * n + 1) DIV 2 = n`] THEN
    REWRITE_TAC[dist; 
VECTOR_SUB_RZERO]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Occasionally useful invariance properties.                                *)
(* ------------------------------------------------------------------------- *)
let CONTINUOUS_AT_COMPOSE_EQ = prove
 (`!f:real^M->real^N g:real^M->real^M h:real^M->real^M.
        g continuous at x /\ h continuous at (g x) /\
        (!y. g(h y) = y) /\ h(g x) = x
        ==> (f continuous at (g x) <=> (\x. f(g x)) continuous at x)`,
  REPEAT STRIP_TAC THEN EQ_TAC THEN
  ASM_SIMP_TAC[REWRITE_RULE[
o_DEF] 
CONTINUOUS_AT_COMPOSE] THEN
  DISCH_TAC THEN
  SUBGOAL_THEN
   `((f:real^M->real^N) o (g:real^M->real^M) o (h:real^M->real^M))
     continuous at (g(x:real^M))`
  MP_TAC THENL
   [REWRITE_TAC[
o_ASSOC] THEN MATCH_MP_TAC 
CONTINUOUS_AT_COMPOSE THEN
    ASM_REWRITE_TAC[
o_DEF];
    ASM_REWRITE_TAC[
o_DEF; ETA_AX]]);;
 
 
add_translation_invariants [CONTINUOUS_AT_TRANSLATION];;
let CONTINUOUS_AT_LINEAR_IMAGE = prove
 (`!h:real^M->real^M z f:real^M->real^N.
        linear h /\ (!x. norm(h x) = norm x)
        ==> (f continuous at (h z) <=> (\x. f(h x)) continuous at z)`,
 
 
add_linear_invariants [CONTINUOUS_AT_LINEAR_IMAGE];;
(* ------------------------------------------------------------------------- *)
(* Interior of an injective image.                                           *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Making a continuous function avoid some value in a neighbourhood.         *)
(* ------------------------------------------------------------------------- *)
let CONTINUOUS_WITHIN_AVOID = prove
 (`!f:real^M->real^N x s a.
        f continuous (at x within s) /\ x 
IN s /\  ~(f x = a)
        ==> ?e. &0 < e /\ !y. y 
IN s /\ dist(x,y) < e ==> ~(f y = a)`,
  REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
continuous_within]) THEN
  DISCH_THEN(MP_TAC o SPEC `norm((f:real^M->real^N) x - a)`) THEN
  ASM_REWRITE_TAC[
NORM_POS_LT; 
VECTOR_SUB_EQ] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN GEN_TAC THEN MATCH_MP_TAC MONO_AND THEN
  REWRITE_TAC[] THEN MATCH_MP_TAC 
MONO_FORALL THEN
  GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN SIMP_TAC[] THEN NORM_ARITH_TAC);;
 
 
let CONTINUOUS_AT_AVOID = prove
 (`!f:real^M->real^N x a.
        f continuous (at x) /\ ~(f x = a)
        ==> ?e. &0 < e /\ !y. dist(x,y) < e ==> ~(f y = a)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Proving a function is constant by proving open-ness of level set.         *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Some arithmetical combinations (more to prove).                           *)
(* ------------------------------------------------------------------------- *)
add_translation_invariants [OPEN_TRANSLATION_EQ];;
add_translation_invariants [INTERIOR_TRANSLATION];;
let OPEN_SUMS = prove
 (`!s t:real^N->bool.
        open s \/ open t ==> open {x + y | x 
IN s /\ y 
IN t}`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
open_def] THEN STRIP_TAC THEN
  REWRITE_TAC[
FORALL_IN_GSPEC] THEN
  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THENL
   [FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`);
    FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`)] THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
  X_GEN_TAC `e:real` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
  X_GEN_TAC `z:real^N` THEN DISCH_TAC THEN REWRITE_TAC[
IN_ELIM_THM] THEN
  ASM_MESON_TAC[
VECTOR_ADD_SYM; VECTOR_ARITH `(z - y) + y:real^N = z`;
                NORM_ARITH `dist(z:real^N,x + y) < e ==> dist(z - y,x) < e`]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Upper and lower hemicontinuous functions, relation in the case of         *)
(* preimage map to open and closed maps, and fact that upper and lower       *)
(* hemicontinuity together imply continuity in the sense of the Hausdorff    *)
(* metric (at points where the function gives a bounded and nonempty set).   *)
(* ------------------------------------------------------------------------- *)
let UPPER_LOWER_HEMICONTINUOUS_EXPLICIT = prove
 (`!f:real^M->real^N->bool t s.
      (!x. x 
IN s ==> f(x) 
SUBSET t) /\
      (!u. 
open_in (subtopology euclidean t) u
           ==> 
open_in (subtopology euclidean s)
                       {x | x 
IN s /\ f(x) 
SUBSET u}) /\
      (!u. 
closed_in (subtopology euclidean t) u
           ==> 
closed_in (subtopology euclidean s)
                         {x | x 
IN s /\ f(x) 
SUBSET u})
      ==> !x e. x 
IN s /\ &0 < e /\ bounded(f x) /\ ~(f x = {})
                ==> ?d. &0 < d /\
                        !x'. x' 
IN s /\ dist(x,x') < d
                             ==> (!y. y 
IN f x
                                      ==> ?y'. y' 
IN f x' /\ dist(y,y') < e) /\
                                 (!y'. y' 
IN f x'
                                       ==> ?y. y 
IN f x /\ dist(y',y) < e)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Connected components, considered as a "connectedness" relation or a set.  *)
(* ------------------------------------------------------------------------- *)
add_translation_invariants [CONNECTED_COMPONENT_TRANSLATION];;
add_linear_invariants [CONNECTED_COMPONENT_LINEAR_IMAGE];;
(* ------------------------------------------------------------------------- *)
(* The set of connected components of a set.                                 *)
(* ------------------------------------------------------------------------- *)
add_translation_invariants [COMPONENTS_TRANSLATION];;
let COMPONENTS_LINEAR_IMAGE = prove
 (`!f s. linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
           ==> components(
IMAGE f s) = 
IMAGE (
IMAGE f) (components s)`,
  REWRITE_TAC[components] THEN GEOM_TRANSFORM_TAC[] THEN SET_TAC[]);;
 
 
add_linear_invariants [COMPONENTS_LINEAR_IMAGE];;
let IN_COMPONENTS = prove
 (`!u:real^N->bool s. s 
IN components u
    <=> ?x. x 
IN u /\ s = 
connected_component u x`,
  REPEAT GEN_TAC THEN REWRITE_TAC[components] THEN EQ_TAC
  THENL [SET_TAC[];STRIP_TAC THEN ASM_SIMP_TAC[] THEN
  UNDISCH_TAC `x:real^N 
IN u` THEN SET_TAC[]]);;
 
 
let COMPONENTS_EQ_SING,COMPONENTS_EQ_SING_EXISTS = (CONJ_PAIR o prove)
 (`(!s:real^N->bool. components s = {s} <=> connected s /\ ~(s = {})) /\
   (!s:real^N->bool. (?a. components s = {a}) <=> connected s /\ ~(s = {}))`,
  REWRITE_TAC[AND_FORALL_THM] THEN X_GEN_TAC `s:real^N->bool` THEN
  MATCH_MP_TAC(TAUT `(p ==> q) /\ (q ==> r) /\ (r ==> p)
                     ==> (p <=> r) /\ (q <=> r)`) THEN
  REPEAT CONJ_TAC THENL
   [MESON_TAC[];
    STRIP_TAC THEN ASM_REWRITE_TAC[CONNECTED_EQ_CONNECTED_COMPONENTS_EQ] THEN
    ASM_MESON_TAC[IN_SING; COMPONENTS_EQ_EMPTY; NOT_INSERT_EMPTY];
    STRIP_TAC THEN ONCE_REWRITE_TAC[EXTENSION] THEN
    REWRITE_TAC[IN_SING] THEN
    REWRITE_TAC[components; IN_ELIM_THM] THEN
    ASM_MESON_TAC[CONNECTED_CONNECTED_COMPONENT_SET; MEMBER_NOT_EMPTY]]);;
let COMPONENTS_UNIQUE = prove
 (`!s:real^N->bool k.
        
UNIONS k = s /\
        (!c. c 
IN k
             ==> connected c /\ ~(c = {}) /\
                 !c'. connected c' /\ c 
SUBSET c' /\ c' 
SUBSET s ==> c' = c)
        ==> components s = k`,
  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC I [
EXTENSION] THEN
  X_GEN_TAC `c:real^N->bool` THEN REWRITE_TAC[
IN_COMPONENTS] THEN
  EQ_TAC THENL
   [DISCH_THEN(X_CHOOSE_THEN `x:real^N`
     (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
    FIRST_ASSUM(MP_TAC o SPEC `x:real^N` o GEN_REWRITE_RULE I [
EXTENSION]) THEN
    REWRITE_TAC[
IN_UNIONS] THEN ASM_REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
    X_GEN_TAC `c:real^N->bool` THEN STRIP_TAC THEN
    SUBGOAL_THEN `
connected_component s (x:real^N) = c`
     (fun th -> ASM_REWRITE_TAC[th]) THEN
    MATCH_MP_TAC 
CONNECTED_COMPONENT_UNIQUE THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `c:real^N->bool`) THEN
    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
    X_GEN_TAC `c':real^N->bool` THEN STRIP_TAC THEN
    REWRITE_TAC[SET_RULE `c' 
SUBSET c <=> c' 
UNION c = c`] THEN
    FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THENL
     [MATCH_MP_TAC 
CONNECTED_UNION; ASM SET_TAC[]] THEN
    ASM SET_TAC[];
    DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `c:real^N->bool`) THEN
    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM 
MEMBER_NOT_EMPTY]) THEN
    MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
    CONJ_TAC THENL [ASM SET_TAC[]; CONV_TAC SYM_CONV] THEN
    FIRST_X_ASSUM MATCH_MP_TAC THEN
    REWRITE_TAC[
CONNECTED_CONNECTED_COMPONENT; 
CONNECTED_COMPONENT_SUBSET] THEN
    MATCH_MP_TAC 
CONNECTED_COMPONENT_MAXIMAL THEN
    ASM_REWRITE_TAC[] THEN ASM SET_TAC[]]);;
 
 
let CLOPEN_IN_COMPONENTS = prove
 (`!u s:real^N->bool.
        
closed_in (subtopology euclidean u) s /\
        
open_in (subtopology euclidean u) s /\
        connected s /\ ~(s = {})
        ==> s 
IN components u`,
  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[
CONJ_ASSOC] THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
CLOPEN_UNIONS_COMPONENTS) THEN
  DISCH_THEN(X_CHOOSE_THEN `k:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
  ASM_CASES_TAC `k:(real^N->bool)->bool = {}` THEN
  ASM_REWRITE_TAC[
UNIONS_0] THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM 
MEMBER_NOT_EMPTY]) THEN
  DISCH_THEN(X_CHOOSE_TAC `c:real^N->bool`) THEN
  ASM_CASES_TAC `k = {c:real^N->bool}` THENL
   [ASM_MESON_TAC[
UNIONS_1; GSYM 
SING_SUBSET]; ALL_TAC] THEN
  MATCH_MP_TAC(TAUT `~p ==> p /\ q ==> r`) THEN
  SUBGOAL_THEN `?c':real^N->bool. c' 
IN k /\ ~(c = c')` STRIP_ASSUME_TAC THENL
   [ASM_MESON_TAC[SET_RULE
     `a 
IN s /\ ~(s = {a}) ==> ?b. b 
IN s /\ ~(b = a)`];
    REWRITE_TAC[
CONNECTED_EQ_CONNECTED_COMPONENTS_EQ] THEN
    DISCH_THEN(MP_TAC o SPECL [`c:real^N->bool`; `c':real^N->bool`]) THEN
    ASM_REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THEN
    MATCH_MP_TAC 
COMPONENTS_INTERMEDIATE_SUBSET THEN
    EXISTS_TAC `u:real^N->bool` THEN
    MP_TAC(ISPEC `u:real^N->bool` 
UNIONS_COMPONENTS) THEN ASM SET_TAC[]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Continuity implies uniform continuity on a compact domain.                *)
(* ------------------------------------------------------------------------- *)
let COMPACT_UNIFORMLY_EQUICONTINUOUS = prove
 (`!(fs:(real^M->real^N)->bool) s.
     (!x e. x 
IN s /\ &0 < e
            ==> ?d. &0 < d /\
                    (!f x'. f 
IN fs /\ x' 
IN s /\ dist (x',x) < d
                            ==> dist (f x',f x) < e)) /\
     compact s
     ==> !e. &0 < e
             ==> ?d. &0 < d /\
                     !f x x'. f 
IN fs /\ x 
IN s /\ x' 
IN s /\ dist (x',x) < d
                              ==> dist(f x',f x) < e`,
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [
RIGHT_IMP_EXISTS_THM] THEN
  REWRITE_TAC[
SKOLEM_THM; 
LEFT_IMP_EXISTS_THM] THEN
  X_GEN_TAC `d:real^M->real->real` THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN
  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o MATCH_MP 
HEINE_BOREL_LEMMA) THEN
  DISCH_THEN(MP_TAC o SPEC
    `{ ball(x:real^M,d x (e / &2)) | x 
IN s}`) THEN
  SIMP_TAC[
FORALL_IN_GSPEC; 
OPEN_BALL; 
UNIONS_GSPEC; 
SUBSET; 
IN_ELIM_THM] THEN
  ANTS_TAC THENL [ASM_MESON_TAC[
CENTRE_IN_BALL; 
REAL_HALF]; ALL_TAC] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `k:real` THEN STRIP_TAC THEN
  ASM_REWRITE_TAC[] THEN
  MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `u:real^M`; `v:real^M`] THEN
  STRIP_TAC THEN FIRST_X_ASSUM(fun th -> MP_TAC(SPEC `v:real^M` th) THEN
    ASM_REWRITE_TAC[] THEN DISCH_THEN(CHOOSE_THEN MP_TAC)) THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  DISCH_THEN(fun th ->
    MP_TAC(SPEC `u:real^M` th) THEN MP_TAC(SPEC `v:real^M` th)) THEN
  ASM_REWRITE_TAC[
DIST_REFL] THEN
  FIRST_X_ASSUM(X_CHOOSE_THEN `w:real^M` (CONJUNCTS_THEN2 ASSUME_TAC
    SUBST_ALL_TAC)) THEN
  ASM_REWRITE_TAC[
CENTRE_IN_BALL] THEN ASM_REWRITE_TAC[
IN_BALL] THEN
  ONCE_REWRITE_TAC[
DIST_SYM] THEN REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`w:real^M`; `e / &2`]) THEN
  ASM_REWRITE_TAC[
REAL_HALF] THEN
  DISCH_THEN(MP_TAC o SPEC `f:real^M->real^N` o CONJUNCT2) THEN
  DISCH_THEN(fun th -> MP_TAC(SPEC `u:real^M` th) THEN
                        MP_TAC(SPEC `v:real^M` th)) THEN
  ASM_REWRITE_TAC[] THEN CONV_TAC NORM_ARITH);;
 
 
(* ------------------------------------------------------------------------- *)
(* A uniformly convergent limit of continuous functions is continuous.       *)
(* ------------------------------------------------------------------------- *)
let CONTINUOUS_UNIFORM_LIMIT = prove
 (`!net f:A->real^M->real^N g s.
        ~(
trivial_limit net) /\
        eventually (\n. (f n) 
continuous_on s) net /\
        (!e. &0 < e
             ==> eventually (\n. !x. x 
IN s ==> norm(f n x - g x) < e) net)
        ==> g 
continuous_on s`,
  REWRITE_TAC[
continuous_on] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
  X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &3`) THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
  FIRST_X_ASSUM(fun th -> MP_TAC th THEN REWRITE_TAC[IMP_IMP] THEN
        GEN_REWRITE_TAC LAND_CONV [GSYM 
EVENTUALLY_AND]) THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
EVENTUALLY_HAPPENS) THEN
  ASM_REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `a:A` THEN
  DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o SPEC `x:real^M`) ASSUME_TAC) THEN
  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `y:real^M` THEN
  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
  FIRST_X_ASSUM(fun th ->
   MP_TAC(SPEC `x:real^M` th) THEN MP_TAC(SPEC `y:real^M` th)) THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
   `w <= x + y + z
    ==> x < e / &3 ==> y < e / &3 ==> z < e / &3 ==> w < e`) THEN
  REWRITE_TAC[dist] THEN
  SUBST1_TAC(VECTOR_ARITH
   `(g:real^M->real^N) y - g x =
    --(f (a:A) y - g y) + (f a x - g x) + (f a y - f a x)`) THEN
  MATCH_MP_TAC 
NORM_TRIANGLE_LE THEN REWRITE_TAC[
NORM_NEG; 
REAL_LE_LADD] THEN
  MATCH_MP_TAC 
NORM_TRIANGLE_LE THEN REWRITE_TAC[
NORM_NEG; 
REAL_LE_REFL]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Topological stuff lifted from and dropped to R                            *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Hence some handy theorems on distance, diameter etc. of/from a set.       *)
(* ------------------------------------------------------------------------- *)
let COMPACT_ATTAINS_SUP = prove
 (`!s. compact (
IMAGE lift s) /\ ~(s = {})
       ==> ?x. x 
IN s /\ !y. y 
IN s ==> y <= x`,
  REWRITE_TAC[
COMPACT_EQ_BOUNDED_CLOSED] THEN REPEAT STRIP_TAC THEN
  MP_TAC(SPEC `s:real->bool` 
BOUNDED_HAS_SUP) THEN ASM_REWRITE_TAC[] THEN
  STRIP_TAC THEN EXISTS_TAC `sup s` THEN ASM_REWRITE_TAC[] THEN
  ASM_MESON_TAC[
CLOSED_LIFT; REAL_ARITH `s <= s - e <=> ~(&0 < e)`;
                REAL_ARITH `x <= s /\ ~(x <= s - e) ==> abs(x - s) < e`]);;
 
 
let COMPACT_ATTAINS_INF = prove
 (`!s. compact (
IMAGE lift s) /\ ~(s = {})
       ==> ?x. x 
IN s /\ !y. y 
IN s ==> x <= y`,
  REWRITE_TAC[
COMPACT_EQ_BOUNDED_CLOSED] THEN REPEAT STRIP_TAC THEN
  MP_TAC(SPEC `s:real->bool` 
BOUNDED_HAS_INF) THEN ASM_REWRITE_TAC[] THEN
  STRIP_TAC THEN EXISTS_TAC `inf s` THEN ASM_REWRITE_TAC[] THEN
  ASM_MESON_TAC[
CLOSED_LIFT; REAL_ARITH `s + e <= s <=> ~(&0 < e)`;
                REAL_ARITH `s <= x /\ ~(s + e <= x) ==> abs(x - s) < e`]);;
 
 
(* ------------------------------------------------------------------------- *)
(* For *minimal* distance, we only need closure, not compactness.            *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* We can now extend limit compositions to consider the scalar multiplier.   *)
(* ------------------------------------------------------------------------- *)
let LIM_MUL = prove
 (`!net:(A)net f l:real^N c d.
        ((lift o c) --> lift d) net /\ (f --> l) net
        ==> ((\x. c(x) % f(x)) --> (d % l)) net`,
  REPEAT STRIP_TAC THEN
  MP_TAC(ISPECL [`net:(A)net`; `\x (y:real^N). drop x % y`;
  `lift o (c:A->real)`; `f:A->real^N`; `lift d`; `l:real^N`] 
LIM_BILINEAR) THEN
  ASM_REWRITE_TAC[
LIFT_DROP; 
o_THM] THEN DISCH_THEN MATCH_MP_TAC THEN
  REWRITE_TAC[bilinear; linear; 
DROP_ADD; 
DROP_CMUL] THEN
  REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC);;
 
 
let LIM_VMUL = prove
 (`!net:(A)net c d v:real^N.
        ((lift o c) --> lift d) net ==> ((\x. c(x) % v) --> d % v) net`,
 
 
let CONTINUOUS_MUL = prove
 (`!net f c. (lift o c) continuous net /\ f continuous net
             ==> (\x. c(x) % f(x)) continuous net`,
 
 
(* ------------------------------------------------------------------------- *)
(* And so we have continuity of inverse.                                     *)
(* ------------------------------------------------------------------------- *)
let LIM_INV = prove
 (`!net:(A)net f l.
        ((lift o f) --> lift l) net /\ ~(l = &0)
        ==> ((lift o inv o f) --> lift(inv l)) net`,
 
 
let CONTINUOUS_INV = prove
 (`!net f. (lift o f) continuous net /\ ~(f(netlimit net) = &0)
           ==> (lift o inv o f) continuous net`,
 
 
(* ------------------------------------------------------------------------- *)
(* More preservation properties for pasted sets (Cartesian products).        *)
(* ------------------------------------------------------------------------- *)
let LIM_PASTECART = prove
 (`!net f:A->real^M g:A->real^N.
        (f --> a) net /\ (g --> b) net
        ==> ((\x. pastecart (f x) (g x)) --> pastecart a b) net`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
LIM] THEN
  ASM_CASES_TAC `
trivial_limit(net:(A)net)` THEN ASM_REWRITE_TAC[] THEN
  REWRITE_TAC[
AND_FORALL_THM] THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN
  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  ASM_REWRITE_TAC[
REAL_HALF] THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
NET_DILEMMA) THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN GEN_TAC THEN MATCH_MP_TAC MONO_AND THEN
  REWRITE_TAC[] THEN MATCH_MP_TAC 
MONO_FORALL THEN GEN_TAC THEN
  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
  REWRITE_TAC[dist; 
PASTECART_SUB] THEN
  MATCH_MP_TAC(REAL_ARITH
    `z <= x + y ==> x < e / &2 /\ y < e / &2 ==> z < e`) THEN
  REWRITE_TAC[
NORM_PASTECART_LE]);;
 
 
let LIM_PASTECART_EQ = prove
 (`!net f:A->real^M g:A->real^N.
        ((\x. pastecart (f x) (g x)) --> pastecart a b) net <=>
        (f --> a) net /\ (g --> b) net`,
 
 
let CONTINUOUS_PASTECART = prove
 (`!net f:A->real^M g:A->real^N.
        f continuous net /\ g continuous net
        ==> (\x. pastecart (f x) (g x)) continuous net`,
 
 
(* ------------------------------------------------------------------------- *)
(* Hence some useful properties follow quite easily.                         *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Hence we get the following.                                               *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* We can state this in terms of diameter of a set.                          *)
(* ------------------------------------------------------------------------- *)
let DIAMETER_BOUNDED = prove
 (`!s. bounded s
       ==> (!x:real^N y. x 
IN s /\ y 
IN s ==> norm(x - y) <= diameter s) /\
           (!d. &0 <= d /\ d < diameter s
                ==> ?x y. x 
IN s /\ y 
IN s /\ norm(x - y) > d)`,
 
 
add_translation_invariants [DIAMETER_TRANSLATION];;
add_linear_invariants [DIAMETER_LINEAR_IMAGE];;
let DIAMETER_POS_LE = prove
 (`!s:real^N->bool. bounded s ==> &0 <= diameter s`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[diameter] THEN
  COND_CASES_TAC THEN ASM_REWRITE_TAC[
REAL_LE_REFL] THEN
  MP_TAC(SPEC `{norm(x - y:real^N) | x 
IN s /\ y 
IN s}` 
SUP) THEN
  REWRITE_TAC[
FORALL_IN_GSPEC] THEN ANTS_TAC THENL
   [CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
    FIRST_X_ASSUM(X_CHOOSE_TAC `B:real` o GEN_REWRITE_RULE I [
BOUNDED_POS]) THEN
    EXISTS_TAC `&2 * B` THEN
    ASM_SIMP_TAC[NORM_ARITH
      `norm x <= B /\ norm y <= B ==> norm(x - y) <= &2 * B`];
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM 
MEMBER_NOT_EMPTY]) THEN
    DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
    DISCH_THEN(MP_TAC o SPECL [`a:real^N`; `a:real^N`] o CONJUNCT1) THEN
    ASM_REWRITE_TAC[
VECTOR_SUB_REFL; 
NORM_0]]);;
 
 
let DIAMETER_SUBSET = prove
 (`!s t:real^N->bool. s 
SUBSET t /\ bounded t ==> diameter s <= diameter t`,
  REPEAT STRIP_TAC THEN
  ASM_CASES_TAC `s:real^N->bool = {}` THEN
  ASM_SIMP_TAC[
DIAMETER_EMPTY; 
DIAMETER_POS_LE] THEN
  ASM_REWRITE_TAC[diameter] THEN
  COND_CASES_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
  MATCH_MP_TAC 
REAL_SUP_LE_SUBSET THEN
  REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
  REWRITE_TAC[
FORALL_IN_GSPEC] THEN
  FIRST_X_ASSUM(X_CHOOSE_TAC `B:real` o GEN_REWRITE_RULE I [
BOUNDED_POS]) THEN
  EXISTS_TAC `&2 * B` THEN
  ASM_SIMP_TAC[NORM_ARITH
    `norm x <= B /\ norm y <= B ==> norm(x - y) <= &2 * B`]);;
 
 
let DIAMETER_CLOSURE = prove
 (`!s:real^N->bool. bounded s ==> diameter(closure s) = diameter s`,
  REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN REPEAT STRIP_TAC THEN
  ASM_SIMP_TAC[
DIAMETER_SUBSET; 
BOUNDED_CLOSURE; 
CLOSURE_SUBSET] THEN
  REWRITE_TAC[GSYM 
REAL_NOT_LT] THEN ONCE_REWRITE_TAC[GSYM 
REAL_SUB_LT] THEN
  DISCH_TAC THEN MP_TAC(ISPEC `closure s:real^N->bool` 
DIAMETER_BOUNDED) THEN
  ABBREV_TAC `d = diameter(closure s) - diameter(s:real^N->bool)` THEN
  ASM_SIMP_TAC[
BOUNDED_CLOSURE] THEN DISCH_THEN(MP_TAC o
    SPEC `diameter(closure(s:real^N->bool)) - d / &2` o CONJUNCT2) THEN
  REWRITE_TAC[NOT_IMP; GSYM 
CONJ_ASSOC; 
NOT_EXISTS_THM] THEN
  FIRST_ASSUM(ASSUME_TAC o MATCH_MP 
DIAMETER_POS_LE) THEN
  REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
  REWRITE_TAC[
CLOSURE_APPROACHABLE; 
CONJ_ASSOC; 
AND_FORALL_THM] THEN
  DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o SPEC `d / &4`) ASSUME_TAC) THEN
  ASM_REWRITE_TAC[REAL_ARITH `&0 < d / &4 <=> &0 < d`] THEN
  DISCH_THEN(CONJUNCTS_THEN2
   (X_CHOOSE_THEN `u:real^N` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC))
   (X_CHOOSE_THEN `v:real^N` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC))) THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
DIAMETER_BOUNDED) THEN
  DISCH_THEN(MP_TAC o SPECL [`u:real^N`; `v:real^N`] o CONJUNCT1) THEN
  ASM_REWRITE_TAC[] THEN REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC);;
 
 
let DIAMETER_EQ_0 = prove
 (`!s:real^N->bool.
        bounded s ==> (diameter s = &0 <=> s = {} \/ ?a. s = {a})`,
  REPEAT STRIP_TAC THEN EQ_TAC THEN STRIP_TAC THEN
  ASM_REWRITE_TAC[
DIAMETER_EMPTY; 
DIAMETER_SING] THEN
  REWRITE_TAC[SET_RULE
   `s = {} \/ (?a. s = {a}) <=> !a b. a 
IN s /\ b 
IN s ==> a = b`] THEN
  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN STRIP_TAC THEN
  MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`; `b:real^N`]
        
DIAMETER_BOUNDED_BOUND) THEN
  ASM_REWRITE_TAC[] THEN NORM_ARITH_TAC);;
 
 
let DIAMETER_LE = prove
 (`!s:real^N->bool.
        (~(s = {}) \/ &0 <= d) /\
        (!x y. x 
IN s /\ y 
IN s ==> norm(x - y) <= d) ==> diameter s <= d`,
  GEN_TAC THEN REWRITE_TAC[diameter] THEN
  COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN
  STRIP_TAC THEN MATCH_MP_TAC 
REAL_SUP_LE THEN
  CONJ_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[
FORALL_IN_GSPEC]]);;
 
 
let DIAMETER_SUMS = prove
 (`!s t:real^N->bool.
        bounded s /\ bounded t
        ==> diameter {x + y | x 
IN s /\ y 
IN t} <= diameter s + diameter t`,
 
 
let LEBESGUE_COVERING_LEMMA = prove
 (`!s:real^N->bool c.
        compact s /\ ~(c = {}) /\ s 
SUBSET UNIONS c /\ (!b. b 
IN c ==> open b)
        ==> ?d. &0 < d /\
                !t. t 
SUBSET s /\ diameter t <= d
                    ==> ?b. b 
IN c /\ t 
SUBSET b`,
  REPEAT STRIP_TAC THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
HEINE_BOREL_LEMMA) THEN
  DISCH_THEN(MP_TAC o SPEC `c:(real^N->bool)->bool`) THEN ASM_SIMP_TAC[] THEN
  ASM_REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `e:real` THEN
  STRIP_TAC THEN EXISTS_TAC `e / &2` THEN ASM_REWRITE_TAC[
REAL_HALF] THEN
  X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
  ASM_CASES_TAC `t:real^N->bool = {}` THENL [ASM SET_TAC[]; ALL_TAC] THEN
  MP_TAC(ISPEC `t:real^N->bool` 
DIAMETER_SUBSET_CBALL_NONEMPTY) THEN
  ANTS_TAC THENL
   [ASM_MESON_TAC[
BOUNDED_SUBSET; 
COMPACT_IMP_BOUNDED]; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
  ANTS_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC 
MONO_EXISTS] THEN
  X_GEN_TAC `b:real^N->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC 
SUBSET_TRANS THEN
  EXISTS_TAC `cball(x:real^N,diameter(t:real^N->bool))` THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
SUBSET_TRANS THEN
  EXISTS_TAC `ball(x:real^N,e)` THEN ASM_REWRITE_TAC[] THEN
  REWRITE_TAC[
SUBSET; 
IN_CBALL; 
IN_BALL] THEN
  MAP_EVERY UNDISCH_TAC [`&0 < e`; `diameter(t:real^N->bool) <= e / &2`] THEN
  NORM_ARITH_TAC);;
 
 
(* ------------------------------------------------------------------------- *)
(* Related results with closure as the conclusion.                           *)
(* ------------------------------------------------------------------------- *)
let CLOSED_NEGATIONS = prove
 (`!s:real^N->bool. closed s ==> closed (
IMAGE (--) s)`,
  REPEAT GEN_TAC THEN
  SUBGOAL_THEN `
IMAGE (--) s = 
IMAGE (\x:real^N. --(&1) % x) s`
  SUBST1_TAC THEN SIMP_TAC[
CLOSED_SCALING] THEN
  REWRITE_TAC[VECTOR_ARITH `--(&1) % x = --x`] THEN REWRITE_TAC[ETA_AX]);;
 
 
let COMPACT_CLOSED_SUMS = prove
 (`!s:real^N->bool t.
        compact s /\ closed t ==> closed {x + y | x 
IN s /\ y 
IN t}`,
  REPEAT GEN_TAC THEN
  REWRITE_TAC[compact; 
IN_ELIM_THM; 
CLOSED_SEQUENTIAL_LIMITS] THEN
  STRIP_TAC THEN X_GEN_TAC `f:num->real^N` THEN X_GEN_TAC `l:real^N` THEN
  REWRITE_TAC[
SKOLEM_THM; 
FORALL_AND_THM] THEN
  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
  DISCH_THEN(X_CHOOSE_THEN `a:num->real^N` MP_TAC) THEN
  DISCH_THEN(X_CHOOSE_THEN `b:num->real^N` STRIP_ASSUME_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o check(is_imp o concl) o SPEC `a:num->real^N`) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `la:real^N` (X_CHOOSE_THEN `sub:num->num`
        STRIP_ASSUME_TAC)) THEN
  MAP_EVERY EXISTS_TAC [`la:real^N`; `l - la:real^N`] THEN
  ASM_REWRITE_TAC[VECTOR_ARITH `a + (b - a) = b:real^N`] THEN
  FIRST_X_ASSUM MATCH_MP_TAC THEN
  EXISTS_TAC `\n. (f o (sub:num->num)) n - (a o sub) n:real^N` THEN
  CONJ_TAC THENL [ASM_REWRITE_TAC[
VECTOR_ADD_SUB; 
o_THM]; ALL_TAC] THEN
  MATCH_MP_TAC 
LIM_SUB THEN ASM_SIMP_TAC[
LIM_SUBSEQUENCE; ETA_AX]);;
 
 
let CLOSURE_SUMS = prove
 (`!s t:real^N->bool.
        bounded s \/ bounded t
        ==> closure {x + y | x 
IN s /\ y 
IN t} =
            {x + y | x 
IN closure s /\ y 
IN closure t}`,
  REWRITE_TAC[TAUT `p \/ q ==> r <=> (p ==> r) /\ (q ==> r)`] THEN
  REWRITE_TAC[
FORALL_AND_THM] THEN
  GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [
SUMS_SYM] THEN
  MATCH_MP_TAC(TAUT `(p ==> q) /\ p ==> p /\ q`) THEN
  SIMP_TAC[] THEN
  REPEAT STRIP_TAC THEN REWRITE_TAC[
EXTENSION; 
CLOSURE_SEQUENTIAL] THEN
  X_GEN_TAC `z:real^N` THEN REWRITE_TAC[
IN_ELIM_THM] THEN EQ_TAC THENL
   [REWRITE_TAC[
IN_ELIM_THM; 
IN_DELETE; 
SKOLEM_THM; 
LEFT_AND_EXISTS_THM] THEN
    REWRITE_TAC[
FORALL_AND_THM] THEN
    ONCE_REWRITE_TAC[TAUT `(p /\ q) /\ r <=> q /\ p /\ r`] THEN
    ONCE_REWRITE_TAC[MESON[] `(?f x y. P f x y) <=> (?x y f. P f x y)`] THEN
    ONCE_REWRITE_TAC[GSYM 
FUN_EQ_THM] THEN
    REWRITE_TAC[ETA_AX; 
UNWIND_THM2] THEN
    REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
    MAP_EVERY X_GEN_TAC [`a:num->real^N`; `b:num->real^N`] THEN
    STRIP_TAC THEN
    MP_TAC(ISPEC `closure s:real^N->bool` compact) THEN
    ASM_REWRITE_TAC[
COMPACT_CLOSURE] THEN
    DISCH_THEN(MP_TAC o SPEC `a:num->real^N`) THEN
    ASM_SIMP_TAC[REWRITE_RULE[
SUBSET] 
CLOSURE_SUBSET; 
LEFT_IMP_EXISTS_THM] THEN
    MAP_EVERY X_GEN_TAC [`u:real^N`; `r:num->num`] THEN STRIP_TAC THEN
    EXISTS_TAC `z - u:real^N` THEN
    EXISTS_TAC `(a:num->real^N) o (r:num->num)` THEN EXISTS_TAC `u:real^N` THEN
    ASM_REWRITE_TAC[
o_THM] THEN
    CONJ_TAC THENL [ALL_TAC; VECTOR_ARITH_TAC] THEN
    EXISTS_TAC `(\n. ((\n. a n + b n) o (r:num->num)) n - (a o r) n)
                :num->real^N` THEN
    CONJ_TAC THENL
     [ASM_REWRITE_TAC[
o_DEF; VECTOR_ARITH `(a + b) - a:real^N = b`];
      MATCH_MP_TAC 
LIM_SUB THEN ASM_REWRITE_TAC[ETA_AX] THEN
      MATCH_MP_TAC 
LIM_SUBSEQUENCE THEN ASM_REWRITE_TAC[]];
    REWRITE_TAC[
LEFT_AND_EXISTS_THM] THEN
    REWRITE_TAC[
LEFT_IMP_EXISTS_THM; 
LEFT_AND_EXISTS_THM;
                
RIGHT_AND_EXISTS_THM] THEN
    MAP_EVERY X_GEN_TAC
     [`x:real^N`; `y:real^N`; `a:num->real^N`; `b:num->real^N`] THEN
    STRIP_TAC THEN EXISTS_TAC `(\n. a n + b n):num->real^N` THEN
    ASM_SIMP_TAC[
LIM_ADD] THEN ASM_MESON_TAC[]]);;
 
 
add_translation_invariants [CLOSED_TRANSLATION_EQ];;
add_translation_invariants [COMPLETE_TRANSLATION_EQ];;
add_translation_invariants [CLOSURE_TRANSLATION];;
add_translation_invariants [FRONTIER_TRANSLATION];;
(* ------------------------------------------------------------------------- *)
(* Separation between points and sets.                                       *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Representing sets as the union of a chain of compact sets.                *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Closed-graph characterization of continuity.                              *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* A cute way of denoting open and closed intervals using overloading.       *)
(* ------------------------------------------------------------------------- *)
let open_interval = new_definition
  `open_interval(a:real^N,b:real^N) =
        {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
                        ==> a$i < x$i /\ x$i < b$i}`;; 
make_overloadable "interval" `:A`;;
overload_interface("interval",`open_interval`);;
overload_interface("interval",`closed_interval`);;
let interval = prove
 (`(interval (a,b) = {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
                                     ==> a$i < x$i /\ x$i < b$i}) /\
   (interval [a,b] = {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
                                     ==> a$i <= x$i /\ x$i <= b$i})`,
 
 
let IN_INTERVAL = prove
 (`(!x:real^N.
        x 
IN interval (a,b) <=>
                !i. 1 <= i /\ i <= dimindex(:N)
                    ==> a$i < x$i /\ x$i < b$i) /\
   (!x:real^N.
        x 
IN interval [a,b] <=>
                !i. 1 <= i /\ i <= dimindex(:N)
                    ==> a$i <= x$i /\ x$i <= b$i)`,
 
 
let INTERVAL_EQ_EMPTY = prove
 (`((interval [a:real^N,b] = {}) <=>
    ?i. 1 <= i /\ i <= dimindex(:N) /\ b$i < a$i) /\
   ((interval (a:real^N,b) = {}) <=>
    ?i. 1 <= i /\ i <= dimindex(:N) /\ b$i <= a$i)`,
 
 
let INTERVAL_NE_EMPTY = prove
 (`(~(interval [a:real^N,b] = {}) <=>
    !i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= b$i) /\
   (~(interval (a:real^N,b) = {}) <=>
    !i. 1 <= i /\ i <= dimindex(:N) ==> a$i < b$i)`,
 
 
let SUBSET_INTERVAL_IMP = prove
 (`((!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)
    ==> interval[c,d] 
SUBSET interval[a:real^N,b]) /\
   ((!i. 1 <= i /\ i <= dimindex(:N) ==> a$i < c$i /\ d$i < b$i)
    ==> interval[c,d] 
SUBSET interval(a:real^N,b)) /\
   ((!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)
    ==> interval(c,d) 
SUBSET interval[a:real^N,b]) /\
   ((!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)
    ==> interval(c,d) 
SUBSET interval(a:real^N,b))`,
  REWRITE_TAC[
SUBSET; 
IN_INTERVAL] THEN REPEAT CONJ_TAC THEN
  DISCH_TAC THEN GEN_TAC THEN POP_ASSUM MP_TAC THEN
  REWRITE_TAC[IMP_IMP; 
AND_FORALL_THM] THEN MATCH_MP_TAC 
MONO_FORALL THEN
  GEN_TAC THEN DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
 
 
let SUBSET_INTERVAL = prove
 (`(interval[c,d] 
SUBSET interval[a:real^N,b] <=>
        (!i. 1 <= i /\ i <= dimindex(:N) ==> c$i <= d$i)
        ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)) /\
   (interval[c,d] 
SUBSET interval(a:real^N,b) <=>
        (!i. 1 <= i /\ i <= dimindex(:N) ==> c$i <= d$i)
        ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i < c$i /\ d$i < b$i)) /\
   (interval(c,d) 
SUBSET interval[a:real^N,b] <=>
        (!i. 1 <= i /\ i <= dimindex(:N) ==> c$i < d$i)
        ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)) /\
   (interval(c,d) 
SUBSET interval(a:real^N,b) <=>
        (!i. 1 <= i /\ i <= dimindex(:N) ==> c$i < d$i)
        ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i))`,
  let lemma = prove
   (`(!x:real^N. (!i. 1 <= i /\ i <= dimindex(:N) ==> Q i (x$i))
                 ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> R i (x$i)))
     ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> ?y. Q i y)
         ==> !i y. 1 <= i /\ i <= dimindex(:N) /\ Q i y ==> R i y`,
    DISCH_TAC THEN REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
    DISCH_THEN(X_CHOOSE_THEN `f:num->real` STRIP_ASSUME_TAC) THEN
    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o
     SPEC `(lambda j. if j = i then y else f j):real^N`) THEN
    SIMP_TAC[LAMBDA_BETA] THEN ASM_MESON_TAC[]) in
  REPEAT STRIP_TAC THEN
  (MATCH_MP_TAC(TAUT
    `(~q ==> p) /\ (q ==> (p <=> r)) ==> (p <=> q ==> r)`) THEN
   CONJ_TAC THENL
    [DISCH_TAC THEN MATCH_MP_TAC(SET_RULE `s = {} ==> s SUBSET t`) THEN
     REWRITE_TAC[INTERVAL_EQ_EMPTY] THEN ASM_MESON_TAC[REAL_NOT_LT];
     ALL_TAC] THEN
   DISCH_TAC THEN EQ_TAC THEN REWRITE_TAC[SUBSET_INTERVAL_IMP] THEN
   REWRITE_TAC[SUBSET; IN_INTERVAL] THEN
   DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN ANTS_TAC THENL
    [ASM_MESON_TAC[REAL_LT_BETWEEN; REAL_LE_BETWEEN]; ALL_TAC] THEN
   MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
   DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
   FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
   ASM_REWRITE_TAC[] THEN POP_ASSUM_LIST(K ALL_TAC) THEN STRIP_TAC)
  THENL
   [ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_REFL];
    ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_REFL];
    ALL_TAC; ALL_TAC] THEN
  (REPEAT STRIP_TAC THENL
    [FIRST_X_ASSUM(MP_TAC o SPEC
      `((c:real^N)$i + min ((a:real^N)$i) ((d:real^N)$i)) / &2`) THEN
     POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
     FIRST_X_ASSUM(MP_TAC o SPEC
      `(max ((b:real^N)$i) ((c:real^N)$i) + (d:real^N)$i) / &2`) THEN
     POP_ASSUM MP_TAC THEN REAL_ARITH_TAC]));;  
 
let DISJOINT_INTERVAL = prove
 (`!a b c d:real^N.
        (interval[a,b] 
INTER interval[c,d] = {} <=>
          ?i. 1 <= i /\ i <= dimindex(:N) /\
              (b$i < a$i \/ d$i < c$i \/ b$i < c$i \/ d$i < a$i)) /\
        (interval[a,b] 
INTER interval(c,d) = {} <=>
          ?i. 1 <= i /\ i <= dimindex(:N) /\
              (b$i < a$i \/ d$i <= c$i \/ b$i <= c$i \/ d$i <= a$i)) /\
        (interval(a,b) 
INTER interval[c,d] = {} <=>
          ?i. 1 <= i /\ i <= dimindex(:N) /\
              (b$i <= a$i \/ d$i < c$i \/ b$i <= c$i \/ d$i <= a$i)) /\
        (interval(a,b) 
INTER interval(c,d) = {} <=>
          ?i. 1 <= i /\ i <= dimindex(:N) /\
              (b$i <= a$i \/ d$i <= c$i \/ b$i <= c$i \/ d$i <= a$i))`,
  REWRITE_TAC[
EXTENSION; 
IN_INTER; 
IN_INTERVAL; 
NOT_IN_EMPTY] THEN
  REWRITE_TAC[
AND_FORALL_THM; 
NOT_FORALL_THM] THEN
  REWRITE_TAC[TAUT `~((p ==> q) /\ (p ==> r)) <=> p /\ (~q \/ ~r)`] THEN
  REWRITE_TAC[DE_MORGAN_THM] THEN REPEAT STRIP_TAC THEN
  (EQ_TAC THENL
    [DISCH_THEN(MP_TAC o SPEC
      `(lambda i. (max ((a:real^N)$i) ((c:real^N)$i) +
                   min ((b:real^N)$i) ((d:real^N)$i)) / &2):real^N`) THEN
     MATCH_MP_TAC 
MONO_EXISTS THEN GEN_TAC THEN
     DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
     ASM_SIMP_TAC[
LAMBDA_BETA] THEN REAL_ARITH_TAC;
     DISCH_THEN(fun th -> GEN_TAC THEN MP_TAC th) THEN
     MATCH_MP_TAC 
MONO_EXISTS THEN GEN_TAC THEN SIMP_TAC[] THEN
     REAL_ARITH_TAC]));;
 
 
let ENDS_IN_INTERVAL = prove
 (`(!a b. a 
IN interval[a,b] <=> ~(interval[a,b] = {})) /\
   (!a b. b 
IN interval[a,b] <=> ~(interval[a,b] = {})) /\
   (!a b. ~(a 
IN interval(a,b))) /\
   (!a b. ~(b 
IN interval(a,b)))`,
 
 
let OPEN_INTERVAL_LEMMA = prove
 (`!a b x. a < x /\ x < b
           ==> ?d. &0 < d /\ !x'. abs(x' - x) < d ==> a < x' /\ x' < b`,
  REPEAT STRIP_TAC THEN
  EXISTS_TAC `min (x - a) (b - x)` THEN REWRITE_TAC[
REAL_LT_MIN] THEN
  ASM_REAL_ARITH_TAC);;
 
 
let CLOSED_INTERVAL = prove
 (`!a:real^N b. closed(interval [a,b])`,
  REWRITE_TAC[
CLOSED_LIMPT; 
LIMPT_APPROACHABLE; 
IN_INTERVAL] THEN
  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM 
REAL_NOT_LT] THEN DISCH_TAC THENL
   [FIRST_X_ASSUM(MP_TAC o SPEC `(a:real^N)$i - (x:real^N)$i`);
    FIRST_X_ASSUM(MP_TAC o SPEC `(x:real^N)$i - (b:real^N)$i`)] THEN
  ASM_REWRITE_TAC[
REAL_SUB_LT] THEN
  DISCH_THEN(X_CHOOSE_THEN `z:real^N` MP_TAC) THEN
  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  REWRITE_TAC[dist; 
REAL_NOT_LT] THEN
  MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `abs((z - x :real^N)$i)` THEN
  ASM_SIMP_TAC[
COMPONENT_LE_NORM] THEN
  ASM_SIMP_TAC[
VECTOR_SUB_COMPONENT] THEN
  ASM_SIMP_TAC[REAL_ARITH `x < a /\ a <= z ==> a - x <= abs(z - x)`;
               REAL_ARITH `z <= b /\ b < x ==> x - b <= abs(z - x)`]);;
 
 
let INTERIOR_CLOSED_INTERVAL = prove
 (`!a:real^N b. interior(interval [a,b]) = interval (a,b)`,
  REPEAT GEN_TAC THEN MATCH_MP_TAC 
SUBSET_ANTISYM THEN CONJ_TAC THENL
   [ALL_TAC;
    MATCH_MP_TAC 
INTERIOR_MAXIMAL THEN
    REWRITE_TAC[
INTERVAL_OPEN_SUBSET_CLOSED; 
OPEN_INTERVAL]] THEN
  REWRITE_TAC[interior; 
SUBSET; 
IN_INTERVAL; 
IN_ELIM_THM] THEN
  X_GEN_TAC `x:real^N` THEN
  DISCH_THEN(X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC) THEN
  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
  ASM_SIMP_TAC[
REAL_LT_LE] THEN REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
open_def]) THEN
  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `e:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THENL
   [(let t = `x - (e / &2) % basis i :real^N` in
     DISCH_THEN(MP_TAC o SPEC t) THEN FIRST_X_ASSUM(MP_TAC o SPEC t));
    (let t = `x + (e / &2) % basis i :real^N` in
     DISCH_THEN(MP_TAC o SPEC t) THEN FIRST_X_ASSUM(MP_TAC o SPEC t))] THEN
  REWRITE_TAC[dist; 
VECTOR_ADD_SUB; VECTOR_ARITH `x - y - x = --y:real^N`] THEN
  ASM_SIMP_TAC[
NORM_MUL; 
NORM_BASIS; 
NORM_NEG; 
REAL_MUL_RID;
               REAL_ARITH `&0 < e ==> abs(e / &2) < e`] THEN
  MATCH_MP_TAC(TAUT `~b ==> (a ==> b) ==> ~a`) THEN
  REWRITE_TAC[
NOT_FORALL_THM] THEN EXISTS_TAC `i:num` THEN
  ASM_SIMP_TAC[DE_MORGAN_THM; 
VECTOR_SUB_COMPONENT; 
VECTOR_ADD_COMPONENT] THENL
   [DISJ1_TAC THEN REWRITE_TAC[REAL_ARITH `a <= a - b <=> ~(&0 < b)`];
    DISJ2_TAC THEN REWRITE_TAC[REAL_ARITH `a + b <= a <=> ~(&0 < b)`]] THEN
  ASM_SIMP_TAC[
VECTOR_MUL_COMPONENT; basis; 
LAMBDA_BETA; 
REAL_MUL_RID] THEN
  ASM_REWRITE_TAC[
REAL_HALF]);;
 
 
let INTERIOR_INTERVAL = prove
 (`(!a b. interior(interval[a,b]) = interval(a,b)) /\
   (!a b. interior(interval(a,b)) = interval(a,b))`,
 
 
let BOUNDED_CLOSED_INTERVAL = prove
 (`!a b:real^N. bounded (interval [a,b])`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[bounded; interval] THEN
  EXISTS_TAC `sum(1..dimindex(:N))
                 (\i. abs((a:real^N)$i) + abs((b:real^N)$i))` THEN
  X_GEN_TAC `x:real^N` THEN REWRITE_TAC[
IN_ELIM_THM] THEN
  STRIP_TAC THEN MATCH_MP_TAC 
REAL_LE_TRANS THEN
  EXISTS_TAC `sum(1..dimindex(:N)) (\i. abs((x:real^N)$i))` THEN
  REWRITE_TAC[
NORM_LE_L1] THEN MATCH_MP_TAC 
SUM_LE THEN
  ASM_SIMP_TAC[
FINITE_NUMSEG; 
IN_NUMSEG; REAL_ARITH
   `a <= x /\ x <= b ==> abs(x) <= abs(a) + abs(b)`]);;
 
 
let CLOSURE_INTERVAL = prove
 (`(!a b. closure(interval[a,b]) = interval[a,b]) /\
   (!a b. closure(interval(a,b)) =
          if interval(a,b) = {} then {} else interval[a,b])`,
 
 
add_translation_invariants
 [CONJUNCT1 INTERVAL_TRANSLATION; CONJUNCT2 INTERVAL_TRANSLATION];;
let IMAGE_STRETCH_INTERVAL = prove
 (`!a b:real^N m.
    
IMAGE (\x. lambda k. m(k) * x$k) (interval[a,b]) =
        if interval[a,b] = {} then {}
        else interval[(lambda k. min (m(k) * a$k) (m(k) * b$k)):real^N,
                      (lambda k. max (m(k) * a$k) (m(k) * b$k))]`,
 
 
let SUMS_INTERVALS = prove
 (`(!a b c d:real^N.
        ~(interval[a,b] = {}) /\ ~(interval[c,d] = {})
        ==> {x + y | x 
IN interval[a,b] /\ y 
IN interval[c,d]} =
            interval[a+c,b+d]) /\
   (!a b c d:real^N.
        ~(interval(a,b) = {}) /\ ~(interval(c,d) = {})
        ==> {x + y | x 
IN interval(a,b) /\ y 
IN interval(c,d)} =
            interval(a+c,b+d))`,
  CONJ_TAC THEN REPEAT GEN_TAC THEN REWRITE_TAC[
INTERVAL_NE_EMPTY] THEN
  STRIP_TAC THEN REWRITE_TAC[
EXTENSION; 
IN_INTERVAL; 
IN_ELIM_THM] THEN
  REWRITE_TAC[TAUT `(a /\ b) /\ c <=> c /\ a /\ b`] THEN
  REWRITE_TAC[VECTOR_ARITH `x:real^N = y + z <=> z = x - y`] THEN
  REWRITE_TAC[
UNWIND_THM2; 
VECTOR_ADD_COMPONENT; 
VECTOR_SUB_COMPONENT] THEN
  (X_GEN_TAC `x:real^N` THEN EQ_TAC THENL
   [DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC);
    DISCH_TAC THEN
    REWRITE_TAC[
AND_FORALL_THM; GSYM 
LAMBDA_SKOLEM;
                TAUT `(p ==> q) /\ (p ==> r) <=> p ==> q /\ r`] THEN
    REWRITE_TAC[REAL_ARITH
     `((a <= y /\ y <= b) /\ c <= x - y /\ x - y <= d <=>
       max a (x - d) <= y /\ y <= min b (x - c)) /\
      ((a < y /\ y < b) /\ c < x - y /\ x - y < d <=>
       max a (x - d) < y /\ y < min b (x - c))`] THEN
    REWRITE_TAC[GSYM 
REAL_LE_BETWEEN; GSYM 
REAL_LT_BETWEEN]] THEN
  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN
  ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC));;
 
 
let PCROSS_INTERVAL = prove
 (`!a b:real^M c d:real^N.
        interval[a,b] 
PCROSS interval[c,d] =
        interval[pastecart a c,pastecart b d]`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
PCROSS] THEN
  REWRITE_TAC[
EXTENSION; 
FORALL_PASTECART; 
IN_ELIM_PASTECART_THM] THEN
  SIMP_TAC[
IN_INTERVAL; pastecart; 
LAMBDA_BETA; 
DIMINDEX_FINITE_SUM] THEN
  MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^N`] THEN EQ_TAC THEN STRIP_TAC THENL
   [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
    COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN
    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
    CONJ_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THENL
     [FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
      DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC;
      FIRST_X_ASSUM(MP_TAC o SPEC `i + dimindex(:M)`) THEN
      COND_CASES_TAC THEN ASM_REWRITE_TAC[
ADD_SUB] THENL
       [ASM_ARITH_TAC;
        DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC]]]);;
 
 
let OPEN_CONTAINS_INTERVAL,OPEN_CONTAINS_OPEN_INTERVAL = (CONJ_PAIR o prove)
 (`(!s:real^N->bool.
        open s <=>
        !x. x IN s ==> ?a b. x IN interval(a,b) /\ interval[a,b] SUBSET s) /\
   (!s:real^N->bool.
        open s <=>
        !x. x IN s ==> ?a b. x IN interval(a,b) /\ interval(a,b) SUBSET s)`,
  REWRITE_TAC[AND_FORALL_THM] THEN GEN_TAC THEN
  MATCH_MP_TAC(TAUT
   `(q ==> r) /\ (r ==> p) /\ (p ==> q) ==> (p <=> q) /\ (p <=> r)`) THEN
  REPEAT CONJ_TAC THENL
   [MESON_TAC[SUBSET_TRANS; INTERVAL_OPEN_SUBSET_CLOSED];
    DISCH_TAC THEN REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN STRIP_TAC THEN
    MP_TAC(ISPEC `interval(a:real^N,b)` OPEN_CONTAINS_BALL) THEN
    REWRITE_TAC[OPEN_INTERVAL] THEN
    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
    MATCH_MP_TAC MONO_EXISTS THEN
    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
    ASM_MESON_TAC[SUBSET_TRANS; INTERVAL_OPEN_SUBSET_CLOSED];
    DISCH_TAC THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
    FIRST_ASSUM(MP_TAC o SPEC `x:real^N` o
      GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
    ASM_REWRITE_TAC[] THEN
    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `x - e / &(dimindex(:N)) % vec 1:real^N` THEN
    EXISTS_TAC `x + e / &(dimindex(:N)) % vec 1:real^N` THEN
    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
     `b SUBSET s ==> x IN i /\ j SUBSET b ==> x IN i /\ j SUBSET s`)) THEN
    SIMP_TAC[IN_INTERVAL; VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT; IN_CBALL;
             VEC_COMPONENT; VECTOR_ADD_COMPONENT; SUBSET; REAL_MUL_RID] THEN
    REWRITE_TAC[REAL_ARITH `x - e < x /\ x < x + e <=> &0 < e`;
                REAL_ARITH `x - e <= y /\ y <= x + e <=> abs(x - y) <= e`] THEN
    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1] THEN
    X_GEN_TAC `y:real^N` THEN REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT] THEN
    DISCH_TAC THEN REWRITE_TAC[dist] THEN
    MATCH_MP_TAC REAL_LE_TRANS THEN
    EXISTS_TAC `sum(1..dimindex(:N)) (\i. abs((x - y:real^N)$i))` THEN
    REWRITE_TAC[NORM_LE_L1] THEN MATCH_MP_TAC SUM_BOUND_GEN THEN
    ASM_SIMP_TAC[CARD_NUMSEG_1; IN_NUMSEG; FINITE_NUMSEG] THEN
    REWRITE_TAC[NUMSEG_EMPTY; NOT_LT; DIMINDEX_GE_1]]);;
let DIAMETER_INTERVAL = prove
 (`(!a b:real^N.
        diameter(interval[a,b]) =
        if interval[a,b] = {} then &0 else norm(b - a)) /\
   (!a b:real^N.
        diameter(interval(a,b)) =
        if interval(a,b) = {} then &0 else norm(b - a))`,
 
 
(* ------------------------------------------------------------------------- *)
(* Some special cases for intervals in R^1.                                  *)
(* ------------------------------------------------------------------------- *)
let IN_INTERVAL_1 = prove
 (`!a b x:real^1.
        (x 
IN interval[a,b] <=> drop a <= drop x /\ drop x <= drop b) /\
        (x 
IN interval(a,b) <=> drop a < drop x /\ drop x < drop b)`,
 
 
let INTERVAL_NE_EMPTY_1 = prove
 (`(!a b:real^1. ~(interval[a,b] = {}) <=> drop a <= drop b) /\
   (!a b:real^1. ~(interval(a,b) = {}) <=> drop a < drop b)`,
 
 
let SUBSET_INTERVAL_1 = prove
 (`!a b c d.
        (interval[a,b] 
SUBSET interval[c,d] <=>
                drop b < drop a \/
                drop c <= drop a /\ drop a <= drop b /\ drop b <= drop d) /\
        (interval[a,b] 
SUBSET interval(c,d) <=>
                drop b < drop a \/
                drop c < drop a /\ drop a <= drop b /\ drop b < drop d) /\
        (interval(a,b) 
SUBSET interval[c,d] <=>
                drop b <= drop a \/
                drop c <= drop a /\ drop a < drop b /\ drop b <= drop d) /\
        (interval(a,b) 
SUBSET interval(c,d) <=>
                drop b <= drop a \/
                drop c <= drop a /\ drop a < drop b /\ drop b <= drop d)`,
 
 
let EQ_INTERVAL_1 = prove
 (`!a b c d:real^1.
       (interval[a,b] = interval[c,d] <=>
          drop b < drop a /\ drop d < drop c \/
          drop a = drop c /\ drop b = drop d)`,
 
 
let DISJOINT_INTERVAL_1 = prove
 (`!a b c d:real^1.
        (interval[a,b] 
INTER interval[c,d] = {} <=>
          drop b < drop a \/ drop d < drop c \/
          drop b < drop c \/ drop d < drop a) /\
        (interval[a,b] 
INTER interval(c,d) = {} <=>
          drop b < drop a \/ drop d <= drop c \/
          drop b <= drop c \/ drop d <= drop a) /\
        (interval(a,b) 
INTER interval[c,d] = {} <=>
          drop b <= drop a \/ drop d < drop c \/
          drop b <= drop c \/ drop d <= drop a) /\
        (interval(a,b) 
INTER interval(c,d) = {} <=>
          drop b <= drop a \/ drop d <= drop c \/
          drop b <= drop c \/ drop d <= drop a)`,
 
 
let BALL_1 = prove
 (`!x:real^1 r. cball(x,r) = interval[x - lift r,x + lift r] /\
                ball(x,r) = interval(x - lift r,x + lift r)`,
 
 
let SPHERE_1 = prove
 (`!a:real^1 r. sphere(a,r) = if r < &0 then {} else {a - lift r,a + lift r}`,
 
 
let BALL_INTERVAL_0 = prove
 (`!e. ball(vec 0:real^1,e) = interval(--lift e,lift e)`,
  GEN_TAC THEN REWRITE_TAC[
BALL_INTERVAL] THEN AP_TERM_TAC THEN
  BINOP_TAC THEN VECTOR_ARITH_TAC);;
 
 
let CBALL_INTERVAL_0 = prove
 (`!e. cball(vec 0:real^1,e) = interval[--lift e,lift e]`,
  GEN_TAC THEN REWRITE_TAC[
CBALL_INTERVAL] THEN AP_TERM_TAC THEN
  AP_THM_TAC THEN AP_TERM_TAC THEN BINOP_TAC THEN VECTOR_ARITH_TAC);;
 
 
let INTER_INTERVAL_1 = prove
 (`!a b c d:real^1.
        interval[a,b] 
INTER interval[c,d] =
        interval[lift(max (drop a) (drop c)),lift(min (drop b) (drop d))]`,
 
 
(* ------------------------------------------------------------------------- *)
(* Intervals in general, including infinite and mixtures of open and closed. *)
(* ------------------------------------------------------------------------- *)
let is_interval = new_definition
  `is_interval(s:real^N->bool) <=>
        !a b x. a IN s /\ b IN s /\
                (!i. 1 <= i /\ i <= dimindex(:N)
                     ==> (a$i <= x$i /\ x$i <= b$i) \/
                         (b$i <= x$i /\ x$i <= a$i))
                ==> x IN s`;; 
add_translation_invariants [IS_INTERVAL_TRANSLATION_EQ];;
let IS_INTERVAL_POINTWISE = prove
 (`!s:real^N->bool x.
        
is_interval s /\
        (!i. 1 <= i /\ i <= dimindex(:N) ==> ?a. a 
IN s /\ a$i = x$i)
        ==> x 
IN s`,
  REWRITE_TAC[
is_interval] THEN REPEAT STRIP_TAC THEN
  SUBGOAL_THEN
    `!n. ?y:real^N. (!i. 1 <= i /\ i <= n ==> y$i = (x:real^N)$i) /\ y 
IN s`
  MP_TAC THENL
   [INDUCT_TAC THEN REWRITE_TAC[ARITH_RULE `~(1 <= i /\ i <= 0)`] THENL
     [ASM_MESON_TAC[
DIMINDEX_GE_1; 
LE_REFL]; ALL_TAC] THEN
    FIRST_X_ASSUM(X_CHOOSE_TAC `y:real^N`) THEN
    ASM_CASES_TAC `SUC n <= dimindex(:N)` THENL
     [FIRST_X_ASSUM(MP_TAC o SPEC `SUC n`) THEN
      ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
      DISCH_THEN(X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC) THEN
      EXISTS_TAC
       `(lambda i. if i <= n then (y:real^N)$i else (z:real^N)$i):real^N` THEN
      CONJ_TAC THENL
       [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
        SUBGOAL_THEN `i <= dimindex(:N)` ASSUME_TAC THENL
         [ASM_ARITH_TAC; ASM_SIMP_TAC[
LAMBDA_BETA]] THEN
        COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
        SUBGOAL_THEN `i = SUC n` (fun th -> ASM_REWRITE_TAC[th]) THEN
        ASM_ARITH_TAC;
        FIRST_X_ASSUM(ASSUME_TAC o CONJUNCT2) THEN
        FIRST_X_ASSUM MATCH_MP_TAC THEN
        MAP_EVERY EXISTS_TAC [`y:real^N`; `z:real^N`] THEN
        ASM_SIMP_TAC[
LAMBDA_BETA] THEN REAL_ARITH_TAC];
      EXISTS_TAC `y:real^N` THEN ASM_REWRITE_TAC[] THEN
      SUBGOAL_THEN `y:real^N = x` (fun th -> REWRITE_TAC[th]) THEN
      REWRITE_TAC[
CART_EQ] THEN
      ASM_MESON_TAC[ARITH_RULE `i <= N /\ ~(SUC n <= N) ==> i <= n`]];
    DISCH_THEN(MP_TAC o SPEC `dimindex(:N)`) THEN
    REWRITE_TAC[GSYM 
CART_EQ] THEN MESON_TAC[]]);;
 
 
let IS_INTERVAL_1_CASES = prove
 (`!s:real^1->bool.
        
is_interval s <=>
        s = {} \/
        s = (:real^1) \/
        (?a. s = {x | a < drop x}) \/
        (?a. s = {x | a <= drop x}) \/
        (?b. s = {x | drop x <= b}) \/
        (?b. s = {x | drop x < b}) \/
        (?a b. s = {x | a < drop x /\ drop x < b}) \/
        (?a b. s = {x | a < drop x /\ drop x <= b}) \/
        (?a b. s = {x | a <= drop x /\ drop x < b}) \/
        (?a b. s = {x | a <= drop x /\ drop x <= b})`,
  GEN_TAC THEN REWRITE_TAC[
IS_INTERVAL_1] THEN EQ_TAC THENL
   [DISCH_TAC;
    STRIP_TAC THEN ASM_REWRITE_TAC[
IN_ELIM_THM; 
IN_UNIV; 
NOT_IN_EMPTY] THEN
    REAL_ARITH_TAC] THEN
  ASM_CASES_TAC `s:real^1->bool = {}` THEN ASM_REWRITE_TAC[] THEN
  MP_TAC(ISPEC `
IMAGE drop s` 
SUP) THEN
  MP_TAC(ISPEC `
IMAGE drop s` 
INF) THEN
  ASM_REWRITE_TAC[
IMAGE_EQ_EMPTY; 
FORALL_IN_IMAGE] THEN
  ASM_CASES_TAC `?a. !x. x 
IN s ==> a <= drop x` THEN
  ASM_CASES_TAC `?b. !x. x 
IN s ==> drop x <= b` THEN
  ASM_REWRITE_TAC[] THENL
   [STRIP_TAC THEN STRIP_TAC THEN
    MAP_EVERY ASM_CASES_TAC
     [`inf(
IMAGE drop s) 
IN IMAGE drop s`; `sup(
IMAGE drop s) 
IN IMAGE drop s`]
    THENL
     [REPLICATE_TAC 8 DISJ2_TAC;
      REPLICATE_TAC 7 DISJ2_TAC THEN DISJ1_TAC;
      REPLICATE_TAC 6 DISJ2_TAC THEN DISJ1_TAC;
      REPLICATE_TAC 5 DISJ2_TAC THEN DISJ1_TAC] THEN
    MAP_EVERY EXISTS_TAC [`inf(
IMAGE drop s)`; `sup(
IMAGE drop s)`];
    STRIP_TAC THEN ASM_CASES_TAC `inf(
IMAGE drop s) 
IN IMAGE drop s` THENL
     [REPLICATE_TAC 2 DISJ2_TAC THEN DISJ1_TAC;
      DISJ2_TAC THEN DISJ1_TAC] THEN
    EXISTS_TAC `inf(
IMAGE drop s)`;
    STRIP_TAC THEN ASM_CASES_TAC `sup(
IMAGE drop s) 
IN IMAGE drop s` THENL
     [REPLICATE_TAC 3 DISJ2_TAC THEN DISJ1_TAC;
      REPLICATE_TAC 4 DISJ2_TAC THEN DISJ1_TAC] THEN
    EXISTS_TAC `sup(
IMAGE drop s)`;
    DISJ1_TAC] THEN
  REWRITE_TAC[
EXTENSION; 
IN_ELIM_THM; 
IN_UNIV] THEN
  RULE_ASSUM_TAC(REWRITE_RULE[
IN_IMAGE]) THEN
  REWRITE_TAC[GSYM 
REAL_NOT_LE] THEN
  ASM_MESON_TAC[
REAL_LE_TRANS; 
REAL_LE_TOTAL; REAL_LE_ANTISYM]);;
 
 
let IS_INTERVAL_PCROSS_EQ = prove
 (`!s:real^M->bool t:real^N->bool.
        
is_interval(s 
PCROSS t) <=>
        s = {} \/ t = {} \/ 
is_interval s /\ 
is_interval t`,
  REPEAT GEN_TAC THEN
  ASM_CASES_TAC `s:real^M->bool = {}` THEN
  ASM_REWRITE_TAC[
PCROSS_EMPTY; 
IS_INTERVAL_EMPTY] THEN
  ASM_CASES_TAC `t:real^N->bool = {}` THEN
  ASM_REWRITE_TAC[
PCROSS_EMPTY; 
IS_INTERVAL_EMPTY] THEN
  EQ_TAC THEN REWRITE_TAC[
IS_INTERVAL_PCROSS] THEN
  REWRITE_TAC[
is_interval] THEN
  REWRITE_TAC[
FORALL_PASTECART; 
PASTECART_IN_PCROSS] THEN
  STRIP_TAC THEN CONJ_TAC THENL
   [MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`; `x:real^M`] THEN
    STRIP_TAC THEN UNDISCH_TAC `~(t:real^N->bool = {})` THEN
    REWRITE_TAC[GSYM 
MEMBER_NOT_EMPTY] THEN
    DISCH_THEN(X_CHOOSE_TAC `y:real^N`) THEN
    FIRST_X_ASSUM(MP_TAC o SPECL
     [`a:real^M`; `y:real^N`; `b:real^M`;
      `y:real^N`; `x:real^M`; `y:real^N`]);
    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`; `x:real^N`] THEN
    STRIP_TAC THEN UNDISCH_TAC `~(s:real^M->bool = {})` THEN
    REWRITE_TAC[GSYM 
MEMBER_NOT_EMPTY] THEN
    DISCH_THEN(X_CHOOSE_TAC `w:real^M`) THEN
    FIRST_X_ASSUM(MP_TAC o SPECL
     [`w:real^M`; `a:real^N`; `w:real^M`;
      `b:real^N`; `w:real^M`; `x:real^N`])] THEN
  ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_MP_TAC THEN
  SIMP_TAC[pastecart; 
LAMBDA_BETA] THEN
  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[
REAL_LE_REFL] THEN
  ASM_MESON_TAC[
DIMINDEX_FINITE_SUM; ARITH_RULE
      `1 <= i /\ i <= m + n /\ ~(i <= m) ==> 1 <= i - m /\ i - m <= n`]);;
 
 
let IS_INTERVAL_SUMS = prove
 (`!s t:real^N->bool.
        
is_interval s /\ 
is_interval t
        ==> 
is_interval {x + y | x 
IN s /\ y 
IN t}`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
is_interval] THEN
  REWRITE_TAC[
IMP_CONJ; 
RIGHT_FORALL_IMP_THM] THEN
  REWRITE_TAC[
FORALL_IN_GSPEC] THEN
  REWRITE_TAC[
RIGHT_IMP_FORALL_THM] THEN
  REWRITE_TAC[IMP_IMP; GSYM 
CONJ_ASSOC] THEN
  MAP_EVERY X_GEN_TAC
   [`a:real^N`; `a':real^N`; `b:real^N`; `b':real^N`; `y:real^N`] THEN
  DISCH_THEN(CONJUNCTS_THEN2
   (MP_TAC o SPECL [`a:real^N`; `b:real^N`]) MP_TAC) THEN
  DISCH_THEN(CONJUNCTS_THEN2
   (MP_TAC o SPECL [`a':real^N`; `b':real^N`]) STRIP_ASSUME_TAC) THEN
  ASM_REWRITE_TAC[IMP_IMP; 
IN_ELIM_THM] THEN  ONCE_REWRITE_TAC[
CONJ_SYM] THEN
  ONCE_REWRITE_TAC[VECTOR_ARITH `z:real^N = x + y <=> y = z - x`] THEN
  REWRITE_TAC[
UNWIND_THM2] THEN MATCH_MP_TAC(MESON[]
   `(?x. P x /\ Q(f x))
    ==> (!x. P x ==> x 
IN s) /\ (!x. Q x ==> x 
IN t)
        ==> ?x. x 
IN s /\ f x 
IN t`) THEN
  REWRITE_TAC[
VECTOR_SUB_COMPONENT; 
AND_FORALL_THM;
              TAUT `(p ==> q) /\ (p ==> r) <=> p ==> q /\ r`] THEN
  REWRITE_TAC[GSYM 
LAMBDA_SKOLEM] THEN
  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
  ASM_REWRITE_TAC[
VECTOR_ADD_COMPONENT] THEN
  REWRITE_TAC[REAL_ARITH
   `c <= y - x /\ y - x <= d <=> y - d <= x /\ x <= y - c`] THEN
  REWRITE_TAC[REAL_ARITH
  `a <= x /\ x <= b \/ b <= x /\ x <= a <=> min a b <= x /\ x <= max a b`] THEN
  ONCE_REWRITE_TAC[TAUT `(p /\ q) /\ (r /\ s) <=> (p /\ r) /\ (q /\ s)`] THEN
  REWRITE_TAC[GSYM 
REAL_LE_MIN; GSYM 
REAL_MAX_LE] THEN
  REWRITE_TAC[GSYM 
REAL_LE_BETWEEN] THEN REAL_ARITH_TAC);;
 
 
(* ------------------------------------------------------------------------- *)
(* Line segments, with same open/closed overloading as for intervals.        *)
(* ------------------------------------------------------------------------- *)
make_overloadable "segment" `:A`;;
overload_interface("segment",`open_segment`);;
overload_interface("segment",`closed_segment`);;
let segment = prove
 (`segment[a,b] = {(&1 - u) % a + u % b | &0 <= u /\ u <= &1} /\
   segment(a,b) = segment[a,b] 
DIFF {a,b}`,
 
 
let SEGMENT_REFL = prove
 (`(!a. segment[a,a] = {a}) /\
   (!a. segment(a,a) = {})`,
  REWRITE_TAC[segment; VECTOR_ARITH `(&1 - u) % a + u % a = a`] THEN
  SET_TAC[
REAL_POS]);;
 
 
let IN_SEGMENT = prove
 (`!a b x:real^N.
        (x 
IN segment[a,b] <=>
         ?u. &0 <= u /\ u <= &1 /\ x = (&1 - u) % a + u % b) /\
        (x 
IN segment(a,b) <=>
         ~(a = b) /\ ?u. &0 < u /\ u < &1 /\ x = (&1 - u) % a + u % b)`,
 
 
let SEGMENT_SYM = prove
 (`(!a b:real^N. segment[a,b] = segment[b,a]) /\
   (!a b:real^N. segment(a,b) = segment(b,a))`,
  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
  SIMP_TAC[
open_segment] THEN
  CONJ_TAC THENL [ALL_TAC; SIMP_TAC[
INSERT_AC]] THEN
  REWRITE_TAC[
EXTENSION; 
IN_SEGMENT] THEN REPEAT GEN_TAC THEN EQ_TAC THEN
  DISCH_THEN(X_CHOOSE_TAC `u:real`) THEN EXISTS_TAC `&1 - u` THEN
  ASM_REWRITE_TAC[] THEN
  REPEAT CONJ_TAC THEN TRY ASM_ARITH_TAC THEN VECTOR_ARITH_TAC);;
 
 
let ENDS_IN_SEGMENT = prove
 (`!a b. a 
IN segment[a,b] /\ b 
IN segment[a,b]`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[segment; 
IN_ELIM_THM] THENL
   [EXISTS_TAC `&0`; EXISTS_TAC `&1`] THEN
  (CONJ_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC]));;
 
 
let MIDPOINT_IN_SEGMENT = prove
 (`(!a b:real^N. midpoint(a,b) 
IN segment[a,b]) /\
   (!a b:real^N. midpoint(a,b) 
IN segment(a,b) <=> ~(a = b))`,
  REWRITE_TAC[
IN_SEGMENT] THEN REPEAT STRIP_TAC THENL
   [ALL_TAC; ASM_CASES_TAC `a:real^N = b` THEN ASM_REWRITE_TAC[]] THEN
  EXISTS_TAC `&1 / &2` THEN REWRITE_TAC[midpoint] THEN
  CONV_TAC REAL_RAT_REDUCE_CONV THEN VECTOR_ARITH_TAC);;
 
 
let BETWEEN_IN_SEGMENT = prove
 (`!x a b:real^N. between x (a,b) <=> x 
IN segment[a,b]`,
  REPEAT GEN_TAC THEN REWRITE_TAC[between] THEN
  ASM_CASES_TAC `a:real^N = b` THEN
  ASM_REWRITE_TAC[
SEGMENT_REFL; 
IN_SING] THENL [NORM_ARITH_TAC; ALL_TAC] THEN
  REWRITE_TAC[segment; 
IN_ELIM_THM] THEN EQ_TAC THENL
   [DISCH_THEN(ASSUME_TAC o SYM) THEN
    EXISTS_TAC `dist(a:real^N,x) / dist(a,b)` THEN
    ASM_SIMP_TAC[
REAL_LE_LDIV_EQ; 
REAL_LE_RDIV_EQ; 
DIST_POS_LT] THEN CONJ_TAC
    THENL [FIRST_ASSUM(SUBST1_TAC o SYM) THEN NORM_ARITH_TAC; ALL_TAC] THEN
    MATCH_MP_TAC 
VECTOR_MUL_LCANCEL_IMP THEN EXISTS_TAC `dist(a:real^N,b)` THEN
    ASM_SIMP_TAC[
VECTOR_MUL_ASSOC; 
VECTOR_ADD_LDISTRIB; 
REAL_SUB_LDISTRIB;
                 
REAL_DIV_LMUL; 
DIST_EQ_0] THEN
    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIST_TRIANGLE_EQ] o SYM) THEN
    FIRST_ASSUM(SUBST1_TAC o SYM) THEN
    REWRITE_TAC[dist; REAL_ARITH `(a + b) * &1 - a = b`] THEN
    VECTOR_ARITH_TAC;
    STRIP_TAC THEN ASM_REWRITE_TAC[dist] THEN
    REWRITE_TAC[VECTOR_ARITH `a - ((&1 - u) % a + u % b) = u % (a - b)`;
                VECTOR_ARITH `((&1 - u) % a + u % b) - b = (&1 - u) % (a - b)`;
                
NORM_MUL; GSYM REAL_ADD_LDISTRIB] THEN
    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD]);;
 
 
let IN_SEGMENT_COMPONENT = prove
 (`!a b x:real^N i.
        x 
IN segment[a,b] /\ 1 <= i /\ i <= dimindex(:N)
        ==> min (a$i) (b$i) <= x$i /\ x$i <= max (a$i) (b$i)`,
  REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
IN_SEGMENT]) THEN
  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
  FIRST_X_ASSUM(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
  ASM_REWRITE_TAC[
VECTOR_ADD_COMPONENT; 
VECTOR_MUL_COMPONENT] THEN
  SIMP_TAC[REAL_ARITH `c <= u * a + t * b <=> u * --a + t * --b <= --c`] THEN
  MATCH_MP_TAC 
REAL_CONVEX_BOUND_LE THEN ASM_REAL_ARITH_TAC);;
 
 
let SEGMENT_1 = prove
 (`(!a b. segment[a,b] =
          if drop a <= drop b then interval[a,b] else interval[b,a]) /\
   (!a b. segment(a,b) =
          if drop a <= drop b then interval(a,b) else interval(b,a))`,
 
 
let SEGMENT_TRANSLATION = prove
 (`(!c a b. segment[c + a,c + b] = 
IMAGE (\x. c + x) (segment[a,b])) /\
   (!c a b. segment(c + a,c + b) = 
IMAGE (\x. c + x) (segment(a,b)))`,
  REWRITE_TAC[
EXTENSION; 
IN_SEGMENT; 
IN_IMAGE] THEN
  REWRITE_TAC[VECTOR_ARITH `(&1 - u) % (c + a) + u % (c + b) =
                            c + (&1 - u) % a + u % b`] THEN
  REWRITE_TAC[VECTOR_ARITH `c + a:real^N = c + b <=> a = b`] THEN
  MESON_TAC[]);;
 
 
add_translation_invariants
 [CONJUNCT1 SEGMENT_TRANSLATION; CONJUNCT2 SEGMENT_TRANSLATION];;
add_linear_invariants [CLOSED_SEGMENT_LINEAR_IMAGE];;
add_linear_invariants [OPEN_SEGMENT_LINEAR_IMAGE];;
let SEGMENT_SCALAR_MULTIPLE = prove
 (`(!a b v. segment[a % v,b % v] =
            {x % v:real^N | a <= x /\ x <= b \/ b <= x /\ x <= a}) /\
   (!a b v. ~(v = vec 0)
            ==> segment(a % v,b % v) =
                {x % v:real^N | a < x /\ x < b \/ b < x /\ x < a})`,
 
 
let FINITE_INTER_COLLINEAR_OPEN_SEGMENTS = prove
 (`!a b c d:real^N.
        collinear{a,b,c}
        ==> (
FINITE(segment(a,b) 
INTER segment(c,d)) <=>
             segment(a,b) 
INTER segment(c,d) = {})`,
  REPEAT GEN_TAC THEN ABBREV_TAC `m:real^N = b - a` THEN POP_ASSUM MP_TAC THEN
  GEOM_NORMALIZE_TAC `m:real^N` THEN
  SIMP_TAC[
VECTOR_SUB_EQ; 
SEGMENT_REFL; 
INTER_EMPTY; 
FINITE_EMPTY] THEN
  X_GEN_TAC `m:real^N` THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
  DISCH_THEN(SUBST_ALL_TAC o SYM) THEN POP_ASSUM MP_TAC THEN
  GEOM_ORIGIN_TAC `a:real^N` THEN GEOM_BASIS_MULTIPLE_TAC 1 `b:real^N` THEN
  X_GEN_TAC `b:real` THEN DISCH_TAC THEN
  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
  SIMP_TAC[
VECTOR_SUB_RZERO; 
NORM_MUL; 
NORM_BASIS; 
DIMINDEX_GE_1; 
LE_REFL] THEN
  ASM_REWRITE_TAC[
real_abs; 
REAL_MUL_RID] THEN DISCH_THEN SUBST_ALL_TAC THEN
  POP_ASSUM(K ALL_TAC) THEN
  ASM_CASES_TAC `collinear{vec 0:real^N,&1 % basis 1,y}` THENL
   [POP_ASSUM MP_TAC THEN
    SIMP_TAC[
COLLINEAR_LEMMA_ALT; 
BASIS_NONZERO; 
DIMINDEX_GE_1; 
LE_REFL] THEN
    MATCH_MP_TAC(TAUT
     `~a /\ (b ==> c ==> d) ==> a \/ b ==> a \/ c ==> d`) THEN
    CONJ_TAC THENL
     [SIMP_TAC[
VECTOR_MUL_LID; 
BASIS_NONZERO; 
DIMINDEX_GE_1; 
LE_REFL];
      REWRITE_TAC[
LEFT_IMP_EXISTS_THM]] THEN
    X_GEN_TAC `b:real` THEN DISCH_THEN SUBST_ALL_TAC THEN
    X_GEN_TAC `a:real` THEN DISCH_THEN SUBST_ALL_TAC THEN
    REWRITE_TAC[
VECTOR_MUL_ASSOC; 
REAL_MUL_RID] THEN
    SUBST1_TAC(VECTOR_ARITH `vec 0:real^N = &0 % basis 1`) THEN
    SIMP_TAC[
SEGMENT_SCALAR_MULTIPLE; 
BASIS_NONZERO; 
DIMINDEX_GE_1; 
LE_REFL;
     
VECTOR_MUL_RCANCEL; 
IMAGE_EQ_EMPTY; 
FINITE_IMAGE_INJ_EQ; SET_RULE
     `(!x y. x % v = y % v <=> x = y)
      ==> {x % v | P x} 
INTER {x % v | Q x} =
          
IMAGE (\x. x % v) {x | P x /\ Q x}`] THEN
    REWRITE_TAC[REAL_ARITH `(&0 < x /\ x < &1 \/ &1 < x /\ x < &0) /\
                            (b < x /\ x < a \/ a < x /\ x < b) <=>
                       max (&0) (min a b) < x /\ x < min (&1) (max a b)`] THEN
    SIMP_TAC[
FINITE_REAL_INTERVAL; 
EXTENSION; 
NOT_IN_EMPTY; 
IN_ELIM_THM] THEN
    SIMP_TAC[GSYM 
REAL_LT_BETWEEN; GSYM 
NOT_EXISTS_THM] THEN REAL_ARITH_TAC;
    DISCH_TAC THEN ASM_CASES_TAC
     `segment(vec 0:real^N,&1 % basis 1) 
INTER segment (x,y) = {}` THEN
    ASM_REWRITE_TAC[
FINITE_EMPTY] THEN DISCH_THEN(K ALL_TAC) THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM 
MEMBER_NOT_EMPTY]) THEN
    REWRITE_TAC[
open_segment; 
IN_DIFF; 
NOT_IN_EMPTY;
                DE_MORGAN_THM; 
IN_INTER; 
IN_INSERT] THEN
    DISCH_THEN(X_CHOOSE_THEN `p:real^N` STRIP_ASSUME_TAC) THEN
    UNDISCH_TAC `~collinear{vec 0:real^N,&1 % basis 1, y}` THEN
    RULE_ASSUM_TAC(REWRITE_RULE[
VECTOR_MUL_LID]) THEN
    REWRITE_TAC[
VECTOR_MUL_LID] THEN
    MATCH_MP_TAC 
COLLINEAR_SUBSET THEN
    EXISTS_TAC `{p,x:real^N, y, vec 0, basis 1}` THEN
    CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
    MP_TAC(ISPECL [`{y:real^N,vec 0,basis 1}`; `p:real^N`; `x:real^N`]
        
COLLINEAR_TRIPLES) THEN
    ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
    REWRITE_TAC[
FORALL_IN_INSERT; 
NOT_IN_EMPTY] THEN CONJ_TAC THENL
     [ONCE_REWRITE_TAC[SET_RULE `{p,x,y} = {x,p,y}`] THEN
      MATCH_MP_TAC 
BETWEEN_IMP_COLLINEAR THEN
      ASM_REWRITE_TAC[
BETWEEN_IN_SEGMENT];
      ALL_TAC] THEN
    ASM_SIMP_TAC[GSYM 
COLLINEAR_4_3] THEN
    ONCE_REWRITE_TAC[SET_RULE `{p,x,z,w} = {w,z,p,x}`] THEN
    SIMP_TAC[
COLLINEAR_4_3; 
BASIS_NONZERO; 
DIMINDEX_GE_1; ARITH] THEN
    REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP 
BETWEEN_IMP_COLLINEAR o
        GEN_REWRITE_RULE I [GSYM 
BETWEEN_IN_SEGMENT])) THEN
    REPEAT(POP_ASSUM MP_TAC) THEN SIMP_TAC[
INSERT_AC]]);;
 
 
let DIST_IN_CLOSED_SEGMENT,DIST_IN_OPEN_SEGMENT = (CONJ_PAIR o prove)
 (`(!a b x:real^N.
    x IN segment[a,b] ==> dist(x,a) <= dist(a,b) /\ dist(x,b) <= dist(a,b)) /\
   (!a b x:real^N.
    x IN segment(a,b) ==> dist(x,a) < dist(a,b) /\ dist(x,b) < dist(a,b))`,
  SIMP_TAC[IN_SEGMENT; RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM; dist;
           VECTOR_ARITH
    `((&1 - u) % a + u % b) - a:real^N = u % (b - a) /\
     ((&1 - u) % a + u % b) - b = --(&1 - u) % (b - a)`] THEN
  REWRITE_TAC[NORM_MUL; REAL_ABS_NEG; NORM_SUB] THEN CONJ_TAC THEN
  REPEAT GEN_TAC THEN STRIP_TAC THENL
   [REWRITE_TAC[REAL_ARITH `x * y <= y <=> x * y <= &1 * y`] THEN
    CONJ_TAC THEN MATCH_MP_TAC REAL_LE_RMUL THEN
    REWRITE_TAC[NORM_POS_LE] THEN ASM_REAL_ARITH_TAC;
    REWRITE_TAC[REAL_ARITH `x * y < y <=> x * y < &1 * y`] THEN
    ASM_SIMP_TAC[REAL_LT_RMUL_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
    ASM_REAL_ARITH_TAC]);;
(* ------------------------------------------------------------------------- *)
(* Limit component bounds.                                                   *)
(* ------------------------------------------------------------------------- *)
let LIM_COMPONENT_LE = prove
 (`!net:(A)net f:A->real^N g:A->real^N k l m.
         ~(
trivial_limit net) /\ (f --> l) net /\ (g --> m) net /\
        eventually (\x. (f x)$k <= (g x)$k) net /\
        1 <= k /\ k <= dimindex(:N)
        ==> l$k <= m$k`,
 
 
let LIM_DROP_LE = prove
 (`!net:(A)net f g l m.
         ~(
trivial_limit net) /\ (f --> l) net /\ (g --> m) net /\
        eventually (\x. drop(f x) <= drop(g x)) net
        ==> drop l <= drop m`,
  REWRITE_TAC[drop] THEN REPEAT STRIP_TAC THEN
  MATCH_MP_TAC(ISPEC `net:(A)net` 
LIM_COMPONENT_LE) THEN
  MAP_EVERY EXISTS_TAC [`f:A->real^1`; `g:A->real^1`] THEN
  ASM_REWRITE_TAC[DIMINDEX_1; 
LE_REFL]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Also extending closed bounds to closures.                                 *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Limits relative to a union.                                               *)
(* ------------------------------------------------------------------------- *)
let LIM_WITHIN_UNION = prove
 (`(f --> l) (at x within (s 
UNION t)) <=>
   (f --> l) (at x within s) /\ (f --> l) (at x within t)`,
  REWRITE_TAC[
LIM_WITHIN; 
IN_UNION; 
AND_FORALL_THM] THEN
  AP_TERM_TAC THEN REWRITE_TAC[
FUN_EQ_THM] THEN X_GEN_TAC `e:real` THEN
  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
  EQ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN DISCH_THEN
   (CONJUNCTS_THEN2 (X_CHOOSE_TAC `d:real`) (X_CHOOSE_TAC `k:real`)) THEN
  EXISTS_TAC `min d k` THEN ASM_REWRITE_TAC[
REAL_LT_MIN] THEN
  ASM_MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Componentwise limits and continuity.                                      *)
(* ------------------------------------------------------------------------- *)
let LIM_COMPONENTWISE_LIFT = prove
 (`!net f:A->real^N.
        (f --> l) net <=>
        !i. 1 <= i /\ i <= dimindex(:N)
            ==> ((\x. lift((f x)$i)) --> lift(l$i)) net`,
 
 
(* ------------------------------------------------------------------------- *)
(* Some more convenient intermediate-value theorem formulations.             *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Rather trivial observation that we can map any connected set on segment.  *)
(* ------------------------------------------------------------------------- *)
let MAPPING_CONNECTED_ONTO_SEGMENT = prove
 (`!s:real^M->bool a b:real^N.
        connected s /\ ~(?a. s 
SUBSET {a})
        ==> ?f. f 
continuous_on s /\ 
IMAGE f s = segment[a,b]`,
  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
   `~(?a. s 
SUBSET {a}) ==> ?a b. a 
IN s /\ b 
IN s /\ ~(a = b)`)) THEN
  REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
  MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`] THEN STRIP_TAC THEN EXISTS_TAC
   `\x:real^M. a + dist(u,x) / (dist(u,x) + dist(v,x)) % (b - a:real^N)` THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC 
CONTINUOUS_ON_ADD THEN REWRITE_TAC[
CONTINUOUS_ON_CONST] THEN
    MATCH_MP_TAC 
CONTINUOUS_ON_MUL THEN SIMP_TAC[
o_DEF; 
CONTINUOUS_ON_CONST];
    REWRITE_TAC[segment; VECTOR_ARITH
     `(&1 - u) % a + u % b:real^N = a + u % (b - a)`] THEN
    MATCH_MP_TAC(SET_RULE
     `
IMAGE f s = {x | P x}
      ==> 
IMAGE (\x. a + f x % b) s = {a + u % b:real^N | P u}`) THEN
    REWRITE_TAC[GSYM 
SUBSET_ANTISYM_EQ; 
SUBSET; 
FORALL_IN_IMAGE] THEN
    ASM_SIMP_TAC[
IN_ELIM_THM; 
REAL_LE_RDIV_EQ; 
REAL_LE_LDIV_EQ;
      NORM_ARITH `~(u:real^N = v) ==> &0 < dist(u,x) + dist(v,x)`] THEN
    CONJ_TAC THENL [CONV_TAC NORM_ARITH; REWRITE_TAC[
IN_IMAGE]] THEN
    X_GEN_TAC `t:real` THEN STRIP_TAC THEN
    MP_TAC(ISPECL
     [`
IMAGE (\x:real^M. lift(dist(u,x) / (dist(u,x) + dist(v,x)))) s`;
      `vec 0:real^1`; `vec 1:real^1`; `t:real`; `1`]
        
CONNECTED_IVT_COMPONENT) THEN
    ASM_SIMP_TAC[
VEC_COMPONENT; DIMINDEX_1; 
ARITH_LE] THEN
    REWRITE_TAC[
EXISTS_IN_IMAGE; GSYM drop; 
LIFT_DROP] THEN
    ANTS_TAC THENL [REWRITE_TAC[
IN_IMAGE]; MESON_TAC[]] THEN
    REPEAT CONJ_TAC THENL
     [MATCH_MP_TAC 
CONNECTED_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[];
      EXISTS_TAC `u:real^M` THEN ASM_REWRITE_TAC[
DIST_REFL; 
real_div] THEN
      REWRITE_TAC[GSYM 
LIFT_NUM; 
LIFT_EQ] THEN REAL_ARITH_TAC;
      EXISTS_TAC `v:real^M` THEN ASM_REWRITE_TAC[
DIST_REFL] THEN
      ASM_SIMP_TAC[
REAL_DIV_REFL; 
DIST_EQ_0; 
REAL_ADD_RID] THEN
      REWRITE_TAC[GSYM 
LIFT_NUM; 
LIFT_EQ]]] THEN
  REWRITE_TAC[
real_div; 
LIFT_CMUL] THEN
  MATCH_MP_TAC 
CONTINUOUS_ON_MUL THEN
  REWRITE_TAC[
CONTINUOUS_ON_LIFT_DIST] THEN
  MATCH_MP_TAC(REWRITE_RULE[
o_DEF] 
CONTINUOUS_ON_INV) THEN
  ASM_SIMP_TAC[
LIFT_ADD; NORM_ARITH
   `~(u:real^N = v) ==> ~(dist(u,x) + dist(v,x) = &0)`] THEN
  MATCH_MP_TAC 
CONTINUOUS_ON_ADD THEN
  REWRITE_TAC[REWRITE_RULE[
o_DEF] 
CONTINUOUS_ON_LIFT_DIST]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Also more convenient formulations of monotone convergence.                *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Since we'll use some cardinality reasoning, add invariance theorems.      *)
(* ------------------------------------------------------------------------- *)
let card_translation_invariants = (CONJUNCTS o prove)
 (`(!a (s:real^N->bool) (t:A->bool).
     IMAGE (\x. a + x) s =_c t <=> s =_c t) /\
   (!a (s:A->bool) (t:real^N->bool).
     s =_c IMAGE (\x. a + x) t <=> s =_c t) /\
   (!a (s:real^N->bool) (t:A->bool).
     IMAGE (\x. a + x) s <_c t <=> s <_c t) /\
   (!a (s:A->bool) (t:real^N->bool).
     s <_c IMAGE (\x. a + x) t <=> s <_c t) /\
   (!a (s:real^N->bool) (t:A->bool).
     IMAGE (\x. a + x) s <=_c t <=> s <=_c t) /\
   (!a (s:A->bool) (t:real^N->bool).
     s <=_c IMAGE (\x. a + x) t <=> s <=_c t) /\
   (!a (s:real^N->bool) (t:A->bool).
     IMAGE (\x. a + x) s >_c t <=> s >_c t) /\
   (!a (s:A->bool) (t:real^N->bool).
     s >_c IMAGE (\x. a + x) t <=> s >_c t) /\
   (!a (s:real^N->bool) (t:A->bool).
     IMAGE (\x. a + x) s >=_c t <=> s >=_c t) /\
   (!a (s:A->bool) (t:real^N->bool).
     s >=_c IMAGE (\x. a + x) t <=> s >=_c t)`,
  REWRITE_TAC[gt_c; ge_c] THEN REPEAT STRIP_TAC THENL
   [MATCH_MP_TAC CARD_EQ_CONG;
    MATCH_MP_TAC CARD_EQ_CONG;
    MATCH_MP_TAC CARD_LT_CONG;
    MATCH_MP_TAC CARD_LT_CONG;
    MATCH_MP_TAC CARD_LE_CONG;
    MATCH_MP_TAC CARD_LE_CONG;
    MATCH_MP_TAC CARD_LT_CONG;
    MATCH_MP_TAC CARD_LT_CONG;
    MATCH_MP_TAC CARD_LE_CONG;
    MATCH_MP_TAC CARD_LE_CONG] THEN
  REWRITE_TAC[CARD_EQ_REFL] THEN MATCH_MP_TAC CARD_EQ_IMAGE THEN
  SIMP_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`]) in
add_translation_invariants card_translation_invariants;;
let card_linear_invariants = (CONJUNCTS o prove)
 (`(!(f:real^M->real^N) s (t:A->bool).
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (IMAGE f s =_c t <=> s =_c t)) /\
   (!(f:real^M->real^N) (s:A->bool) t.
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (s =_c IMAGE f t <=> s =_c t)) /\
   (!(f:real^M->real^N) s (t:A->bool).
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (IMAGE f s <_c t <=> s <_c t)) /\
   (!(f:real^M->real^N) (s:A->bool) t.
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (s <_c IMAGE f t <=> s <_c t)) /\
   (!(f:real^M->real^N) s (t:A->bool).
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (IMAGE f s <=_c t <=> s <=_c t)) /\
   (!(f:real^M->real^N) (s:A->bool) t.
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (s <=_c IMAGE f t <=> s <=_c t)) /\
   (!(f:real^M->real^N) s (t:A->bool).
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (IMAGE f s >_c t <=> s >_c t)) /\
   (!(f:real^M->real^N) (s:A->bool) t.
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (s >_c IMAGE f t <=> s >_c t)) /\
   (!(f:real^M->real^N) s (t:A->bool).
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (IMAGE f s >=_c t <=> s >=_c t)) /\
   (!(f:real^M->real^N) (s:A->bool) t.
     linear f /\ (!x y. f x = f y ==> x = y)
     ==> (s >=_c IMAGE f t <=> s >=_c t))`,
  REWRITE_TAC[gt_c; ge_c] THEN REPEAT STRIP_TAC THENL
   [MATCH_MP_TAC CARD_EQ_CONG;
    MATCH_MP_TAC CARD_EQ_CONG;
    MATCH_MP_TAC CARD_LT_CONG;
    MATCH_MP_TAC CARD_LT_CONG;
    MATCH_MP_TAC CARD_LE_CONG;
    MATCH_MP_TAC CARD_LE_CONG;
    MATCH_MP_TAC CARD_LT_CONG;
    MATCH_MP_TAC CARD_LT_CONG;
    MATCH_MP_TAC CARD_LE_CONG;
    MATCH_MP_TAC CARD_LE_CONG] THEN
  REWRITE_TAC[CARD_EQ_REFL] THEN MATCH_MP_TAC CARD_EQ_IMAGE THEN
  ASM_MESON_TAC[]) in
add_linear_invariants card_linear_invariants;;
(* ------------------------------------------------------------------------- *)
(* Basic homeomorphism definitions.                                          *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("homeomorphic",(12,"right"));;
let HOMEOMORPHISM_SYM = prove
 (`!f:real^M->real^N g s t.
        homeomorphism (s,t) (f,g) <=> homeomorphism (t,s) (g,f)`,
  REWRITE_TAC[homeomorphism] THEN MESON_TAC[]);;
 
 
let HOMEOMORPHIC_SYM = prove
 (`!s t. s homeomorphic t <=> t homeomorphic s`,
  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphic; homeomorphism] THEN
  GEN_REWRITE_TAC RAND_CONV [
SWAP_EXISTS_THM] THEN
  REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN CONV_TAC TAUT);;
 
 
let HOMEOMORPHISM_COMPOSE = prove
 (`!f:real^M->real^N g h:real^N->real^P k s t u.
        homeomorphism (s,t) (f,g) /\ homeomorphism (t,u) (h,k)
        ==> homeomorphism (s,u) (h o f,g o k)`,
 
 
let HOMEOMORPHIC_TRANS = prove
 (`!s:real^M->bool t:real^N->bool u:real^P->bool.
        s homeomorphic t /\ t homeomorphic u ==> s homeomorphic u`,
 
 
let HOMEOMORPHIC_EMPTY = prove
 (`(!s. (s:real^N->bool) homeomorphic ({}:real^M->bool) <=> s = {}) /\
   (!s. ({}:real^M->bool) homeomorphic (s:real^N->bool) <=> s = {})`,
 
 
add_linear_invariants
  [HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ;
   HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ];;
add_translation_invariants
  [HOMEOMORPHIC_TRANSLATION_LEFT_EQ;
   HOMEOMORPHIC_TRANSLATION_RIGHT_EQ];;
(* ------------------------------------------------------------------------- *)
(* Inverse function property for open/closed maps.                           *)
(* ------------------------------------------------------------------------- *)
let CONTINUOUS_ON_INVERSE_OPEN_MAP = prove
 (`!f:real^M->real^N g s t.
        f 
continuous_on s /\ 
IMAGE f s = t /\ (!x. x 
IN s ==> g(f x) = x) /\
        (!u. 
open_in (subtopology euclidean s) u
             ==> 
open_in (subtopology euclidean t) (
IMAGE f u))
        ==> g 
continuous_on t`,
  REPEAT STRIP_TAC THEN
  MP_TAC(ISPECL [`g:real^N->real^M`; `t:real^N->bool`; `s:real^M->bool`]
        
CONTINUOUS_ON_OPEN_GEN) THEN
  ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN SUBST1_TAC] THEN
  X_GEN_TAC `u:real^M->bool` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `u:real^M->bool`) THEN ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
  FIRST_ASSUM(MP_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [
open_in]) THEN
  ASM SET_TAC[]);;
 
 
let HOMEOMORPHISM_IMP_OPEN_MAP = prove
 (`!f:real^M->real^N g s t u.
        homeomorphism (s,t) (f,g) /\ 
open_in (subtopology euclidean s) u
        ==> 
open_in (subtopology euclidean t) (
IMAGE f u)`,
  REWRITE_TAC[homeomorphism] THEN REPEAT STRIP_TAC THEN
  SUBGOAL_THEN `
IMAGE (f:real^M->real^N) u =
                 {y | y 
IN t /\ g(y) 
IN u}`
  SUBST1_TAC THENL
   [FIRST_ASSUM(MP_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [
open_in]) THEN
    ASM SET_TAC[];
    MATCH_MP_TAC 
CONTINUOUS_ON_IMP_OPEN_IN THEN ASM_REWRITE_TAC[]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Relatively weak hypotheses if the domain of the function is compact.      *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Lemmas about composition of homeomorphisms.                               *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Preservation of topological properties.                                   *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Results on translation, scaling etc.                                      *)
(* ------------------------------------------------------------------------- *)
let [HOMEOMORPHIC_BALLS; HOMEOMORPHIC_CBALLS; HOMEOMORPHIC_SPHERES] =
  (CONJUNCTS o prove)
 (`(!a:real^N b:real^N d e.
      &0 < d /\ &0 < e ==> ball(a,d) homeomorphic ball(b,e)) /\
   (!a:real^N b:real^N d e.
      &0 < d /\ &0 < e ==> cball(a,d) homeomorphic cball(b,e)) /\
   (!a:real^N b:real^N d e.
      &0 < d /\ &0 < e ==> sphere(a,d) homeomorphic sphere(b,e))`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
  EXISTS_TAC `\x:real^N. b + (e / d) % (x - a)` THEN
  EXISTS_TAC `\x:real^N. a + (d / e) % (x - b)` THEN
  ASM_SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_SUB; CONTINUOUS_ON_CMUL;
    CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID; IN_BALL; IN_CBALL; IN_SPHERE] THEN
  REWRITE_TAC[dist; VECTOR_ARITH `a - (a + b) = --b:real^N`; NORM_NEG] THEN
  REWRITE_TAC[real_div; VECTOR_ARITH
   `a + d % ((b + e % (x - a)) - b) = (&1 - d * e) % a + (d * e) % x`] THEN
  ONCE_REWRITE_TAC[REAL_ARITH
    `(e * d') * (d * e') = (d * d') * (e * e')`] THEN
  ASM_SIMP_TAC[REAL_MUL_RINV; REAL_LT_IMP_NZ; REAL_MUL_LID; REAL_SUB_REFL] THEN
  REWRITE_TAC[NORM_MUL; VECTOR_MUL_LZERO; VECTOR_MUL_LID; VECTOR_ADD_LID] THEN
  ASM_SIMP_TAC[REAL_ABS_MUL; REAL_ABS_INV; REAL_ARITH
   `&0 < x ==> (abs x = x)`] THEN
  GEN_REWRITE_TAC(BINOP_CONV o BINDER_CONV o funpow 2 RAND_CONV)
        [GSYM REAL_MUL_RID] THEN
  ONCE_REWRITE_TAC[AC REAL_MUL_AC `(a * b) * c = (a * c) * b`] THEN
  ASM_SIMP_TAC[REAL_LE_LMUL_EQ; GSYM real_div; REAL_LE_LDIV_EQ; REAL_MUL_LID;
    GSYM REAL_MUL_ASSOC; REAL_LT_LMUL_EQ; REAL_LT_LDIV_EQ; NORM_SUB] THEN
  ASM_SIMP_TAC[REAL_DIV_REFL; REAL_LT_IMP_NZ; REAL_MUL_RID]);;
(* ------------------------------------------------------------------------- *)
(* Homeomorphism of one-point compactifications.                             *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Homeomorphisms between open intervals in real^1 and then in real^N.       *)
(* Could prove similar things for closed intervals, but they drop out of     *)
(* later stuff in "convex.ml" even more easily.                              *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Cardinalities of various useful sets.                                     *)
(* ------------------------------------------------------------------------- *)
let CARD_EQ_INTERVAL = prove
 (`(!a b:real^N. ~(interval(a,b) = {}) ==> interval[a,b] =_c (:real)) /\
   (!a b:real^N. ~(interval(a,b) = {}) ==> interval(a,b) =_c (:real))`,
 
 
let UNCOUNTABLE_INTERVAL = prove
 (`(!a b. ~(interval(a,b) = {}) ==> ~COUNTABLE(interval[a,b])) /\
   (!a b. ~(interval(a,b) = {}) ==> ~COUNTABLE(interval(a,b)))`,
 
 
(* ------------------------------------------------------------------------- *)
(* "Iff" forms of constancy of function from connected set into a set that   *)
(* is smaller than R, or countable, or finite, or disconnected, or discrete. *)
(* ------------------------------------------------------------------------- *)
let [CONTINUOUS_DISCONNECTED_RANGE_CONSTANT_EQ;
     CONTINUOUS_DISCRETE_RANGE_CONSTANT_EQ;
     CONTINUOUS_FINITE_RANGE_CONSTANT_EQ] = (CONJUNCTS o prove)
  (`(!s. connected s <=>
         !f:real^M->real^N t.
            f continuous_on s /\ IMAGE f s SUBSET t /\
            (!y. y IN t ==> connected_component t y = {y})
            ==> ?a. !x. x IN s ==> f x = a) /\
    (!s. connected s <=>
         !f:real^M->real^N.
            f continuous_on s /\
            (!x. x IN s
                 ==> ?e. &0 < e /\
                         !y. y IN s /\ ~(f y = f x) ==> e <= norm(f y - f x))
            ==> ?a. !x. x IN s ==> f x = a) /\
    (!s. connected s <=>
         !f:real^M->real^N.
            f continuous_on s /\ FINITE(IMAGE f s)
            ==> ?a. !x. x IN s ==> f x = a)`,
  REWRITE_TAC[AND_FORALL_THM] THEN X_GEN_TAC `s:real^M->bool` THEN
  MATCH_MP_TAC(TAUT
   `(s ==> t) /\ (t ==> u) /\ (u ==> v) /\ (v ==> s)
    ==> (s <=> t) /\ (s <=> u) /\ (s <=> v)`) THEN
  REPEAT CONJ_TAC THENL
   [REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN
    ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
    FIRST_X_ASSUM(X_CHOOSE_TAC `x:real^M` o
        GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
    EXISTS_TAC `(f:real^M->real^N) x` THEN
    MATCH_MP_TAC(SET_RULE
     `IMAGE f s SUBSET {a} ==> !y. y IN s ==> f y = a`) THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `(f:real^M->real^N) x`) THEN
    ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN(SUBST1_TAC o SYM)] THEN
    MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
    ASM_SIMP_TAC[CONNECTED_CONTINUOUS_IMAGE] THEN ASM SET_TAC[];
    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
    EXISTS_TAC `IMAGE (f:real^M->real^N) s` THEN
    ASM_REWRITE_TAC[FORALL_IN_IMAGE; SUBSET_REFL] THEN
    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
    MATCH_MP_TAC(SET_RULE
     `(!y. y IN s /\ f y IN connected_component (IMAGE f s) a ==> f y = a) /\
      connected_component (IMAGE f s) a SUBSET (IMAGE f s) /\
      connected_component (IMAGE f s) a a
      ==> connected_component (IMAGE f s) a = {a}`) THEN
    REWRITE_TAC[CONNECTED_COMPONENT_SUBSET; CONNECTED_COMPONENT_REFL_EQ] THEN
    ASM_SIMP_TAC[FUN_IN_IMAGE] THEN X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
    MP_TAC(ISPEC `connected_component (IMAGE (f:real^M->real^N) s) (f x)`
        CONNECTED_CLOSED) THEN
    REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT] THEN
    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
    ASM_REWRITE_TAC[] THEN MAP_EVERY EXISTS_TAC
     [`cball((f:real^M->real^N) x,e / &2)`;
      `(:real^N) DIFF ball((f:real^M->real^N) x,e)`] THEN
    REWRITE_TAC[GSYM OPEN_CLOSED; OPEN_BALL; CLOSED_CBALL] THEN
    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN REPEAT CONJ_TAC THENL
     [REWRITE_TAC[SUBSET; IN_CBALL; IN_UNION; IN_DIFF; IN_BALL; IN_UNIV] THEN
      MATCH_MP_TAC(MESON[SUBSET; CONNECTED_COMPONENT_SUBSET]
       `(!x. x IN s ==> P x)
        ==> (!x. x IN connected_component s y ==> P x)`) THEN
      REWRITE_TAC[FORALL_IN_IMAGE] THEN X_GEN_TAC `z:real^M` THEN
      DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `z:real^M`) THEN
      ASM_REWRITE_TAC[] THEN CONV_TAC NORM_ARITH;
      MATCH_MP_TAC(SET_RULE
       `(!x. x IN s /\ x IN t ==> F) ==> s INTER t INTER u = {}`) THEN
      REWRITE_TAC[IN_BALL; IN_CBALL; IN_DIFF; IN_UNIV] THEN
      UNDISCH_TAC `&0 < e` THEN CONV_TAC NORM_ARITH;
      EXISTS_TAC `(f:real^M->real^N) x` THEN
      ASM_SIMP_TAC[CENTRE_IN_CBALL; REAL_HALF; REAL_LT_IMP_LE; IN_INTER] THEN
      REWRITE_TAC[IN] THEN
      ASM_SIMP_TAC[CONNECTED_COMPONENT_REFL_EQ; FUN_IN_IMAGE];
      EXISTS_TAC `(f:real^M->real^N) y` THEN
      ASM_REWRITE_TAC[IN_INTER; IN_DIFF; IN_UNIV; IN_BALL; REAL_NOT_LT] THEN
      ASM_SIMP_TAC[ONCE_REWRITE_RULE[DIST_SYM] dist]];
    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `f:real^M->real^N` THEN
    DISCH_THEN(fun th -> STRIP_TAC THEN MATCH_MP_TAC th) THEN
    ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
    ASM_CASES_TAC `IMAGE (f:real^M->real^N) s DELETE (f x) = {}` THENL
     [EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN ASM SET_TAC[];
      ALL_TAC] THEN
    EXISTS_TAC
     `inf{norm(z - f x) |z| z IN IMAGE (f:real^M->real^N) s DELETE (f x)}` THEN
    REWRITE_TAC[SIMPLE_IMAGE] THEN
    ASM_SIMP_TAC[REAL_LT_INF_FINITE; REAL_INF_LE_FINITE; FINITE_DELETE;
                 FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
    REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
    REWRITE_TAC[IN_DELETE; NORM_POS_LT; VECTOR_SUB_EQ; IN_IMAGE] THEN
    MESON_TAC[REAL_LE_REFL];
    REWRITE_TAC[CONNECTED_CLOSED_IN_EQ] THEN
    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
    MAP_EVERY X_GEN_TAC [`t:real^M->bool`; `u:real^M->bool`] THEN
    STRIP_TAC THEN DISCH_THEN(MP_TAC o SPEC
     `(\x. if x IN t then vec 0 else basis 1):real^M->real^N`) THEN
    REWRITE_TAC[NOT_IMP] THEN REPEAT CONJ_TAC THENL
     [EXPAND_TAC "s" THEN MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN
      ASM_REWRITE_TAC[CONTINUOUS_ON_CONST] THEN ASM SET_TAC[];
      MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `{vec 0:real^N,basis 1}` THEN
      REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY] THEN SET_TAC[];
      SUBGOAL_THEN `?a b:real^M. a IN s /\ a IN t /\ b IN s /\ ~(b IN t)`
      STRIP_ASSUME_TAC THENL
       [ASM SET_TAC[]; DISCH_THEN(CHOOSE_THEN MP_TAC)] THEN
      DISCH_THEN(fun th -> MP_TAC(SPEC `a:real^M` th) THEN
                           MP_TAC(SPEC `b:real^M` th)) THEN
      ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
      CONV_TAC(RAND_CONV SYM_CONV) THEN
      SIMP_TAC[BASIS_NONZERO; LE_REFL; DIMINDEX_GE_1; REAL_LE_REFL]]]);;
(* ------------------------------------------------------------------------- *)
(* Homeomorphism of hyperplanes.                                             *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* "Isometry" (up to constant bounds) of injective linear map etc.           *)
(* ------------------------------------------------------------------------- *)
let CAUCHY_ISOMETRIC = prove
 (`!f s e x.
        &0 < e /\ subspace s /\
        linear f /\ (!x. x 
IN s ==> norm(f x) >= e * norm(x)) /\
        (!n. x(n) 
IN s) /\ cauchy(f o x)
        ==> cauchy x`,
 
 
let INJECTIVE_IMP_ISOMETRIC = prove
 (`!f:real^M->real^N s.
        closed s /\ subspace s /\
        linear f /\ (!x. x 
IN s /\ (f x = vec 0) ==> (x = vec 0))
        ==> ?e. &0 < e /\ !x. x 
IN s ==> norm(f x) >= e * norm(x)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Relating linear images to open/closed/interior/closure.                   *)
(* ------------------------------------------------------------------------- *)
add_linear_invariants [OPEN_BIJECTIVE_LINEAR_IMAGE_EQ];;
add_linear_invariants [CLOSED_INJECTIVE_LINEAR_IMAGE_EQ];;
add_linear_invariants [CLOSURE_INJECTIVE_LINEAR_IMAGE];;
add_linear_invariants [INTERIOR_BIJECTIVE_LINEAR_IMAGE];;
add_linear_invariants [FRONTIER_BIJECTIVE_LINEAR_IMAGE];;
(* ------------------------------------------------------------------------- *)
(* Corollaries, reformulations and special cases for M = N.                  *)
(* ------------------------------------------------------------------------- *)
add_linear_invariants [COMPLETE_INJECTIVE_LINEAR_IMAGE_EQ];;
add_linear_invariants [LIMPT_INJECTIVE_LINEAR_IMAGE_EQ];;
add_translation_invariants [LIMPT_TRANSLATION_EQ];;
(* ------------------------------------------------------------------------- *)
(* Even more special cases.                                                  *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Some properties of a canonical subspace.                                  *)
(* ------------------------------------------------------------------------- *)
let DIM_SUBSTANDARD = prove
 (`!d. d <= dimindex(:N)
       ==> (dim {x:real^N | !i. d < i /\ i <= dimindex(:N)
                                ==> x$i = &0} =
            d)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Hence closure and completeness of all subspaces.                          *)
(* ------------------------------------------------------------------------- *)
let CLOSED_SUBSPACE = prove
 (`!s:real^N->bool. subspace s ==> closed s`,
  REPEAT STRIP_TAC THEN ABBREV_TAC `d = dim(s:real^N->bool)` THEN
  MP_TAC(MATCH_MP 
DIM_SUBSTANDARD
    (ISPEC `s:real^N->bool` 
DIM_SUBSET_UNIV)) THEN
  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
  MP_TAC(ISPECL
   [`{x:real^N | !i. d < i /\ i <= dimindex(:N)
                                ==> x$i = &0}`;
    `s:real^N->bool`] 
SUBSPACE_ISOMORPHISM) THEN
  ASM_REWRITE_TAC[
SUBSPACE_SUBSTANDARD] THEN
  DISCH_THEN(X_CHOOSE_THEN `f:real^N->real^N` MP_TAC) THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  DISCH_THEN(CONJUNCTS_THEN2 (SUBST_ALL_TAC o SYM) STRIP_ASSUME_TAC) THEN
  MATCH_MP_TAC(ISPEC `f:real^N->real^N` 
CLOSED_INJECTIVE_IMAGE_SUBSPACE) THEN
  ASM_REWRITE_TAC[
SUBSPACE_SUBSTANDARD; 
CLOSED_SUBSTANDARD] THEN
  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
  ASM_REWRITE_TAC[] THEN
  CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[
LINEAR_0]] THEN
  REWRITE_TAC[
IN_ELIM_THM] THEN
  ASM_MESON_TAC[
VEC_COMPONENT; ARITH_RULE `d < i ==> 1 <= i`]);;
 
 
let BASIS_COORDINATES_LIPSCHITZ = prove
 (`!b:real^N->bool.
        independent b
        ==> ?B. &0 < B /\
                !c v. v 
IN b
                      ==> abs(c v) <= B * norm(vsum b (\v. c(v) % v))`,
  X_GEN_TAC `k:real^N->bool` THEN DISCH_TAC THEN
  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP 
INDEPENDENT_BOUND) THEN
  FIRST_ASSUM(X_CHOOSE_THEN `b:num->real^N` STRIP_ASSUME_TAC o
        GEN_REWRITE_RULE I [
FINITE_INDEX_NUMSEG]) THEN
  ABBREV_TAC `n = 
CARD(k:real^N->bool)` THEN
  MP_TAC(ISPECL
   [`(\x. vsum(1..n) (\i. x$i % b i)):real^N->real^N`;
    `span(
IMAGE basis (1..n)):real^N->bool`]
        
INJECTIVE_IMP_ISOMETRIC) THEN
  REWRITE_TAC[
SUBSPACE_SPAN] THEN ANTS_TAC THENL
   [CONJ_TAC THENL [SIMP_TAC[
CLOSED_SUBSPACE; 
SUBSPACE_SPAN]; ALL_TAC] THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC 
LINEAR_COMPOSE_VSUM THEN
      REWRITE_TAC[
FINITE_NUMSEG; 
IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
      MATCH_MP_TAC 
LINEAR_VMUL_COMPONENT THEN
      SIMP_TAC[
LINEAR_ID] THEN ASM_ARITH_TAC;
      ALL_TAC] THEN
    X_GEN_TAC `x:real^N` THEN
    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
IN_SPAN_IMAGE_BASIS]) THEN
    REWRITE_TAC[
IN_NUMSEG] THEN DISCH_TAC THEN
    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
INJECTIVE_ON_LEFT_INVERSE]) THEN
    DISCH_THEN(X_CHOOSE_TAC `c:real^N->num`) THEN
    SUBGOAL_THEN
     `vsum(1..n) (\i. (x:real^N)$i % b i:real^N) = vsum k (\v. x$(c v) % v)`
    SUBST1_TAC THENL
     [MATCH_MP_TAC 
VSUM_EQ_GENERAL_INVERSES THEN
      MAP_EVERY EXISTS_TAC [`b:num->real^N`; `c:real^N->num`] THEN
      ASM SET_TAC[];
      ALL_TAC] THEN
    DISCH_TAC THEN
    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
INDEPENDENT_EXPLICIT]) THEN
    DISCH_THEN(MP_TAC o SPEC `\v:real^N. (x:real^N)$(c v)` o CONJUNCT2) THEN
    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
    REWRITE_TAC[
CART_EQ; 
FORALL_IN_IMAGE; 
VEC_COMPONENT] THEN
    ASM_MESON_TAC[
IN_NUMSEG];
    ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `inv(B:real)` THEN ASM_REWRITE_TAC[
REAL_LT_INV_EQ] THEN
  ASM_REWRITE_TAC[
FORALL_IN_IMAGE; 
IN_NUMSEG] THEN
  MAP_EVERY X_GEN_TAC [`c:real^N->real`; `j:num`] THEN STRIP_TAC THEN
  ONCE_REWRITE_TAC[REAL_ARITH `inv B * x = x / B`] THEN
  ASM_SIMP_TAC[
REAL_LE_RDIV_EQ] THEN
  W(MP_TAC o PART_MATCH (lhs o rand) 
VSUM_IMAGE o rand o rand o snd) THEN
  ASM_REWRITE_TAC[
FINITE_NUMSEG] THEN DISCH_THEN SUBST1_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC
   `(lambda i. if 1 <= i /\ i <= n then c(b i:real^N) else &0):real^N`) THEN
  SIMP_TAC[
IN_SPAN_IMAGE_BASIS; 
LAMBDA_BETA] THEN
  ANTS_TAC THENL [MESON_TAC[
IN_NUMSEG]; ALL_TAC] THEN
  MATCH_MP_TAC(REAL_ARITH `x = v /\ u <= y ==> x >= y ==> u <= v`) THEN
  CONJ_TAC THENL
   [AP_TERM_TAC THEN MATCH_MP_TAC 
VSUM_EQ_NUMSEG THEN
    SUBGOAL_THEN `!i. i <= n ==> i <= dimindex(:N)` MP_TAC THENL
     [ASM_ARITH_TAC; SIMP_TAC[
LAMBDA_BETA] THEN DISCH_THEN(K ALL_TAC)] THEN
    REWRITE_TAC[
o_THM];
    GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
    ASM_SIMP_TAC[
REAL_LE_RMUL_EQ] THEN
    MP_TAC(ISPECL
     [`(lambda i. if 1 <= i /\ i <= n then c(b i:real^N) else &0):real^N`;
      `j:num`] 
COMPONENT_LE_NORM) THEN
    SUBGOAL_THEN `1 <= j /\ j <= dimindex(:N)` MP_TAC THENL
     [ASM_ARITH_TAC; SIMP_TAC[
LAMBDA_BETA] THEN ASM_REWRITE_TAC[]]]);;
 
 
let BASIS_COORDINATES_CONTINUOUS = prove
 (`!b:real^N->bool e.
        independent b /\ &0 < e
        ==> ?d. &0 < d /\
                !c. norm(vsum b (\v. c(v) % v)) < d
                    ==> !v. v 
IN b ==> abs(c v) < e`,
  REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o MATCH_MP 
BASIS_COORDINATES_LIPSCHITZ) THEN
  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `e / B:real` THEN ASM_SIMP_TAC[
REAL_LT_DIV] THEN
  X_GEN_TAC `c:real^N->real` THEN DISCH_TAC THEN
  X_GEN_TAC `v:real^N` THEN DISCH_TAC THEN
  MATCH_MP_TAC 
REAL_LET_TRANS THEN
  EXISTS_TAC `B * norm(vsum b (\v:real^N. c v % v))` THEN
  ASM_SIMP_TAC[] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
  ASM_SIMP_TAC[GSYM 
REAL_LT_RDIV_EQ]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Affine transformations of intervals.                                      *)
(* ------------------------------------------------------------------------- *)
let AFFINITY_INVERSES = prove
 (`!m c. ~(m = &0)
         ==> (\x. m % x + c) o (\x. inv(m) % x + (--(inv(m) % c))) = I /\
             (\x. inv(m) % x + (--(inv(m) % c))) o (\x. m % x + c) = I`,
 
 
let REAL_AFFINITY_LE = prove
 (`!m c x y. &0 < m ==> (m * x + c <= y <=> x <= inv(m) * y + --(c / m))`,
  REWRITE_TAC[REAL_ARITH `m * x + c <= y <=> x * m <= y - c`] THEN
  SIMP_TAC[GSYM 
REAL_LE_RDIV_EQ] THEN REAL_ARITH_TAC);;
 
 
let REAL_LE_AFFINITY = prove
 (`!m c x y. &0 < m ==> (y <= m * x + c <=> inv(m) * y + --(c / m) <= x)`,
  REWRITE_TAC[REAL_ARITH `y <= m * x + c <=> y - c <= x * m`] THEN
  SIMP_TAC[GSYM 
REAL_LE_LDIV_EQ] THEN REAL_ARITH_TAC);;
 
 
let REAL_AFFINITY_EQ = prove
 (`!m c x y. ~(m = &0) ==> (m * x + c = y <=> x = inv(m) * y + --(c / m))`,
  CONV_TAC REAL_FIELD);;
 
 
let REAL_EQ_AFFINITY = prove
 (`!m c x y. ~(m = &0) ==> (y = m * x + c  <=> inv(m) * y + --(c / m) = x)`,
  CONV_TAC REAL_FIELD);;
 
 
let IMAGE_AFFINITY_INTERVAL = prove
 (`!a b:real^N m c.
        
IMAGE (\x. m % x + c) (interval[a,b]) =
            if interval[a,b] = {} then {}
            else if &0 <= m then interval[m % a + c,m % b + c]
            else interval[m % b + c,m % a + c]`,
 
 
(* ------------------------------------------------------------------------- *)
(* Existence of eigenvectors. The proof is only in this file because it uses *)
(* a few simple results about continuous functions (at least                 *)
(* CONTINUOUS_ON_LIFT_DOT2, CONTINUOUS_ATTAINS_SUP and CLOSED_SUBSPACE).     *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Diagonalization of symmetric matrix.                                      *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Some matrix identities are easier to deduce for invertible matrices. We   *)
(* can then extend by continuity, which is why this material needs to be     *)
(* here after basic topological notions have been defined.                   *)
(* ------------------------------------------------------------------------- *)
let CONTINUOUS_LIFT_DET = prove
 (`!(A:A->real^N^N) net.
        (!i j. 1 <= i /\ i <= dimindex(:N) /\
               1 <= j /\ j <= dimindex(:N)
               ==> (\x. lift(A x$i$j)) continuous net)
        ==> (\x. lift(det(A x))) continuous net`,
 
 
let MATRIX_WLOG_INVERTIBLE = prove
 (`!P. (!A:real^N^N. invertible A ==> P A) /\
       (!A:real^N^N. ?d. &0 < d /\
                         closed {x | x 
IN cball(vec 0,d) /\
                                     P(A + drop x %% mat 1)})
       ==> !A:real^N^N. P A`,
 
 
 "B'"] THEN
      SIMP_TAC[CART_EQ; LAMBDA_BETA; matrix_mul] THEN REPEAT STRIP_TAC THEN
      MATCH_MP_TAC SUM_EQ_SUPERSET THEN
      ASM_SIMP_TAC[IN_NUMSEG; REAL_MUL_LZERO; FINITE_NUMSEG; SUBSET_NUMSEG;
                   LE_REFL; TAUT `(p /\ q) /\ ~(p /\ r) <=> p /\ q /\ ~r`];
      DISCH_THEN(SUBST1_TAC o SYM)] THEN
    REWRITE_TAC[det] THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
     `sum {p | p permutes 1..dimindex(:N) /\ !i. dimindex(:M) < i ==> p i = i}
          (\p. sign p * product (1..dimindex(:N))
                     (\i. (mat 1 + (A':real^N^N) ** (B':real^N^N))$i$p i))` THEN
    CONJ_TAC THENL
     [ALL_TAC;
      CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_SUPERSET THEN
      CONJ_TAC THENL [SET_TAC[]; SIMP_TAC[IN_ELIM_THM; IMP_CONJ]] THEN
      X_GEN_TAC `p:num->num` THEN REPEAT STRIP_TAC THEN
      REWRITE_TAC[REAL_ENTIRE; PRODUCT_EQ_0_NUMSEG] THEN DISJ2_TAC THEN
      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:num` THEN
      REWRITE_TAC[NOT_IMP] THEN STRIP_TAC THEN
      FIRST_ASSUM(MP_TAC o SPEC `k:num` o CONJUNCT1 o
        GEN_REWRITE_RULE I [permutes]) THEN
      ASM_REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
      FIRST_ASSUM(MP_TAC o MATCH_MP PERMUTES_IMAGE) THEN
      DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE `s = t ==> s SUBSET t`)) THEN
      ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_NUMSEG] THEN
      DISCH_THEN(MP_TAC o SPEC `k:num`) THEN ASM_SIMP_TAC[] THEN STRIP_TAC THEN
      ASM_SIMP_TAC[MATRIX_ADD_COMPONENT; MAT_COMPONENT; REAL_ADD_LID] THEN
      ASM_SIMP_TAC[matrix_mul; LAMBDA_BETA] THEN
      MATCH_MP_TAC SUM_EQ_0_NUMSEG THEN REPEAT STRIP_TAC THEN
      REWRITE_TAC[REAL_ENTIRE] THEN DISJ1_TAC THEN EXPAND_TAC "A'" THEN
      ASM_SIMP_TAC[LAMBDA_BETA; GSYM NOT_LT]] THEN
    CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_EQ_GENERAL THEN
    EXISTS_TAC `\f:num->num. f` THEN REWRITE_TAC[IN_ELIM_THM] THEN
    CONJ_TAC THEN X_GEN_TAC `p:num->num` THEN STRIP_TAC THENL
     [REWRITE_TAC[MESON[] `(?!x. P x /\ x = y) <=> P y`] THEN CONJ_TAC THENL
       [MATCH_MP_TAC PERMUTES_SUBSET THEN
        EXISTS_TAC `1..dimindex(:M)` THEN
        ASM_REWRITE_TAC[SUBSET_NUMSEG; LE_REFL];
        X_GEN_TAC `k:num` THEN DISCH_TAC THEN
        FIRST_X_ASSUM(MATCH_MP_TAC o CONJUNCT1 o
          GEN_REWRITE_RULE I [permutes]) THEN
        ASM_REWRITE_TAC[IN_NUMSEG; DE_MORGAN_THM; NOT_LE]];
      MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
       [MATCH_MP_TAC PERMUTES_SUPERSET THEN
        EXISTS_TAC `1..dimindex(:N)` THEN
        ASM_REWRITE_TAC[IN_DIFF; IN_NUMSEG] THEN ASM_MESON_TAC[NOT_LE];
        DISCH_TAC] THEN
      AP_TERM_TAC THEN FIRST_ASSUM(SUBST1_TAC o MATCH_MP (ARITH_RULE
       `m:num <= n ==> n = m + (n - m)`)) THEN
      SIMP_TAC[PRODUCT_ADD_SPLIT; ARITH_RULE `1 <= n + 1`] THEN
      MATCH_MP_TAC(REAL_RING `x = y /\ z = &1 ==> x = y * z`) THEN
      CONJ_TAC THENL
       [MATCH_MP_TAC PRODUCT_EQ_NUMSEG THEN
        X_GEN_TAC `i:num` THEN STRIP_TAC THEN
        SUBGOAL_THEN `i <= dimindex(:N)` ASSUME_TAC THENL
         [ASM_ARITH_TAC; ALL_TAC] THEN
        MP_TAC(ISPECL [`p:num->num`; `1..dimindex(:M)`] PERMUTES_IMAGE) THEN
        ASM_REWRITE_TAC[] THEN
        DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE `s = t ==> s SUBSET t`)) THEN
        ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_NUMSEG] THEN
        DISCH_THEN(MP_TAC o SPEC `i:num`) THEN
        ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
        SUBGOAL_THEN `(p:num->num) i <= dimindex(:N)` ASSUME_TAC THENL
         [ASM_ARITH_TAC; ALL_TAC] THEN
        ASM_SIMP_TAC[MATRIX_ADD_COMPONENT; MAT_COMPONENT] THEN
        AP_TERM_TAC THEN ASM_SIMP_TAC[matrix_mul; LAMBDA_BETA] THEN
        MATCH_MP_TAC SUM_EQ_NUMSEG THEN REPEAT STRIP_TAC THEN
        MAP_EVERY EXPAND_TAC ["A'"; "B'"] THEN
        ASM_SIMP_TAC[LAMBDA_BETA];
        MATCH_MP_TAC PRODUCT_EQ_1_NUMSEG THEN
        ASM_SIMP_TAC[ARITH_RULE `n + 1 <= i ==> n < i`] THEN
        ASM_SIMP_TAC[ARITH_RULE `m:num <= n ==> m + (n - m) = n`] THEN
        X_GEN_TAC `i:num` THEN STRIP_TAC THEN
        SUBGOAL_THEN `1 <= i` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
        ASM_SIMP_TAC[MATRIX_ADD_COMPONENT; MAT_COMPONENT] THEN
        ASM_SIMP_TAC[REAL_EQ_ADD_LCANCEL_0; matrix_mul; LAMBDA_BETA] THEN
        MATCH_MP_TAC SUM_EQ_0_NUMSEG THEN REPEAT STRIP_TAC THEN
        REWRITE_TAC[REAL_ENTIRE] THEN DISJ1_TAC THEN EXPAND_TAC "A'" THEN
        ASM_SIMP_TAC[LAMBDA_BETA; ARITH_RULE `m + 1 <= i ==> ~(i <= m)`]]]) in
  REPEAT GEN_TAC THEN DISJ_CASES_TAC (ARITH_RULE
   `dimindex(:M) <= dimindex(:N) \/ dimindex(:N) <= dimindex(:M)`)
  THENL [ALL_TAC; CONV_TAC SYM_CONV] THEN
  MATCH_MP_TAC lemma2 THEN ASM_REWRITE_TAC[]);;
let COFACTOR_COFACTOR = prove
 (`!A:real^N^N.
     2 <= dimindex(:N)
     ==> cofactor(cofactor A) = (det(A) pow (dimindex(:N) - 2)) %% A`,
 
 
let RANK_COFACTOR = prove
 (`!A:real^N^N.
        rank(cofactor A) = if rank(A) = dimindex(:N) then dimindex(:N)
                           else if rank(A) = dimindex(:N) - 1 then 1
                           else 0`,
 
 
(* ------------------------------------------------------------------------- *)
(* Not in so many words, but combining this with intermediate value theorem  *)
(* implies the determinant is an open map.                                   *)
(* ------------------------------------------------------------------------- *)
let DET_OPEN_MAP = prove
 (`!A:real^N^N e.
        &0 < e
        ==> (?B:real^N^N. (!i j. abs(B$i$j - A$i$j) < e) /\ det B < det A) /\
            (?C:real^N^N. (!i j. abs(C$i$j - A$i$j) < e) /\ det C > det A)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Infinite sums of vectors. Allow general starting point (and more).        *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("sums",(12,"right"));;
let SUMS_SUMMABLE = prove
 (`!f l s. (f sums l) s ==> summable s f`,
  REWRITE_TAC[summable] THEN MESON_TAC[]);;
 
 
let SUMS_INFSUM = prove
 (`!f s. (f sums (infsum s f)) s <=> summable s f`,
  REWRITE_TAC[infsum; summable] THEN MESON_TAC[]);;
 
 
let SUMS_LIM = prove
 (`!f:num->real^N s.
      (f sums lim sequentially (\n. vsum (s 
INTER (0..n)) f)) s
      <=> summable s f`,
  GEN_TAC THEN GEN_TAC THEN EQ_TAC THENL [MESON_TAC[summable];
  REWRITE_TAC[summable; sums] THEN STRIP_TAC THEN REWRITE_TAC[lim] THEN
  ASM_MESON_TAC[]]);;
 
 
let SERIES_FROM = prove
 (`!f l k. (f sums l) (from k) = ((\n. vsum(k..n) f) --> l) sequentially`,
  REPEAT GEN_TAC THEN REWRITE_TAC[sums] THEN
  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
  AP_THM_TAC THEN AP_TERM_TAC THEN
  REWRITE_TAC[
EXTENSION; numseg; from; 
IN_ELIM_THM; 
IN_INTER] THEN ARITH_TAC);;
 
 
let SERIES_TERMS_TOZERO = prove
 (`!f l n. (f sums l) (from n) ==> (f --> vec 0) sequentially`,
  REPEAT GEN_TAC THEN SIMP_TAC[sums; 
LIM_SEQUENTIALLY; 
FROM_INTER_NUMSEG] THEN
  DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  ASM_REWRITE_TAC[
REAL_HALF] THEN DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN
  EXISTS_TAC `N + n + 1` THEN X_GEN_TAC `m:num` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(fun th ->
    MP_TAC(SPEC `m - 1` th) THEN MP_TAC(SPEC `m:num` th)) THEN
  SUBGOAL_THEN `0 < m /\ n <= m` (fun th -> SIMP_TAC[
VSUM_CLAUSES_RIGHT; th])
  THENL [ASM_ARITH_TAC; ALL_TAC] THEN
  REPEAT(ANTS_TAC THENL [ASM_ARITH_TAC; DISCH_TAC]) THEN
  REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC);;
 
 
let SERIES_ADD = prove
 (`!x x0 y y0 s.
     (x sums x0) s /\ (y sums y0) s ==> ((\n. x n + y n) sums (x0 + y0)) s`,
 
 
let SERIES_SUB = prove
 (`!x x0 y y0 s.
     (x sums x0) s /\ (y sums y0) s ==> ((\n. x n - y n) sums (x0 - y0)) s`,
 
 
let SUMS_IFF = prove
 (`!f g k. (!x. x 
IN k ==> f x = g x) ==> ((f sums l) k <=> (g sums l) k)`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[sums] THEN
  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
  MATCH_MP_TAC 
VSUM_EQ THEN ASM_SIMP_TAC[
IN_INTER]);;
 
 
let SUMS_EQ = prove
 (`!f g k. (!x. x 
IN k ==> f x = g x) /\ (f sums l) k ==> (g sums l) k`,
 
 
let SUMS_0 = prove
 (`!f:num->real^N s. (!n. n 
IN s ==> f n = vec 0) ==> (f sums vec 0) s`,
  REPEAT STRIP_TAC THEN MATCH_MP_TAC 
SUMS_EQ THEN
  EXISTS_TAC `\n:num. vec 0:real^N` THEN ASM_SIMP_TAC[
SERIES_0]);;
 
 
let SERIES_COMPONENT = prove
 (`!f s l:real^N k. (f sums l) s /\ 1 <= k /\ k <= dimindex(:N)
                    ==> ((\i. lift(f(i)$k)) sums lift(l$k)) s`,
 
 
let SERIES_DIFFS = prove
 (`!f:num->real^N k.
        (f --> vec 0) sequentially
        ==> ((\n. f(n) - f(n + 1)) sums f(k)) (from k)`,
 
 
let SERIES_RESTRICT = prove
 (`!f k l:real^N.
        ((\n. if n 
IN k then f(n) else vec 0) sums l) (:num) <=>
        (f sums l) k`,
  REPEAT GEN_TAC THEN REWRITE_TAC[sums] THEN
  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
  REWRITE_TAC[
FUN_EQ_THM; 
INTER_UNIV] THEN GEN_TAC THEN
  MATCH_MP_TAC(MESON[] `vsum s f = vsum t f /\ vsum t f = vsum t g
                        ==> vsum s f = vsum t g`) THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC 
VSUM_SUPERSET THEN SET_TAC[];
    MATCH_MP_TAC 
VSUM_EQ THEN SIMP_TAC[
IN_INTER]]);;
 
 
let SUMS_REINDEX = prove
 (`!k a l n. ((\x. a(x + k)) sums l) (from n) <=> (a sums l) (from(n + k))`,
  REPEAT GEN_TAC THEN REWRITE_TAC[sums; 
FROM_INTER_NUMSEG] THEN
  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM 
VSUM_OFFSET] THEN
  REWRITE_TAC[
LIM_SEQUENTIALLY] THEN
  ASM_MESON_TAC[ARITH_RULE `N + k:num <= n ==> n = (n - k) + k /\ N <= n - k`;
                ARITH_RULE `N + k:num <= n ==> N <= n + k`]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Similar combining theorems just for summability.                          *)
(* ------------------------------------------------------------------------- *)
let SUMMABLE_EQ = prove
 (`!f g k. (!x. x 
IN k ==> f x = g x) /\ summable k f ==> summable k g`,
  REWRITE_TAC[summable] THEN MESON_TAC[
SUMS_EQ]);;
 
 
let SUMMABLE_COMPONENT = prove
 (`!f:num->real^N s k.
        summable s f /\ 1 <= k /\ k <= dimindex(:N)
        ==> summable s (\i. lift(f(i)$k))`,
  REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(X_CHOOSE_TAC `l:real^N` o REWRITE_RULE[summable]) THEN
  REWRITE_TAC[summable] THEN EXISTS_TAC `lift((l:real^N)$k)` THEN
  ASM_SIMP_TAC[
SERIES_COMPONENT]);;
 
 
let SERIES_SUBSET = prove
 (`!x s t l.
        s 
SUBSET t /\
        ((\i. if i 
IN s then x i else vec 0) sums l) t
        ==> (x sums l) s`,
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  REWRITE_TAC[sums] THEN MATCH_MP_TAC EQ_IMP THEN
  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
  ASM_SIMP_TAC[GSYM 
VSUM_RESTRICT_SET; 
FINITE_INTER_NUMSEG] THEN
  AP_THM_TAC THEN AP_TERM_TAC THEN POP_ASSUM MP_TAC THEN SET_TAC[]);;
 
 
let SUMS_FINITE_DIFF = prove
 (`!f:num->real^N t s l.
        t 
SUBSET s /\ 
FINITE t /\ (f sums l) s
        ==> (f sums (l - vsum t f)) (s 
DIFF t)`,
  REPEAT GEN_TAC THEN
  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  FIRST_ASSUM(MP_TAC o ISPEC `f:num->real^N` o MATCH_MP 
SERIES_FINITE) THEN
  ONCE_REWRITE_TAC[GSYM 
SERIES_RESTRICT] THEN
  REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[
CONJ_SYM] THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
SERIES_SUB) THEN
  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
  REWRITE_TAC[
FUN_EQ_THM] THEN X_GEN_TAC `x:num` THEN REWRITE_TAC[
IN_DIFF] THEN
  FIRST_ASSUM(MP_TAC o SPEC `x:num` o GEN_REWRITE_RULE I [
SUBSET]) THEN
  MAP_EVERY ASM_CASES_TAC [`(x:num) 
IN s`; `(x:num) 
IN t`] THEN
  ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
 
 
let SUMS_FINITE_UNION = prove
 (`!f:num->real^N s t l.
        
FINITE t /\ (f sums l) s
        ==> (f sums (l + vsum (t 
DIFF s) f)) (s 
UNION t)`,
  REPEAT GEN_TAC THEN
  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  FIRST_ASSUM(MP_TAC o SPEC `s:num->bool` o MATCH_MP 
FINITE_DIFF) THEN
  DISCH_THEN(MP_TAC o ISPEC `f:num->real^N` o MATCH_MP 
SERIES_FINITE) THEN
  ONCE_REWRITE_TAC[GSYM 
SERIES_RESTRICT] THEN
  REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[
CONJ_SYM] THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
SERIES_ADD) THEN
  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
  REWRITE_TAC[
FUN_EQ_THM] THEN X_GEN_TAC `x:num` THEN
  REWRITE_TAC[
IN_DIFF; 
IN_UNION] THEN
  MAP_EVERY ASM_CASES_TAC [`(x:num) 
IN s`; `(x:num) 
IN t`] THEN
  ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
 
 
let SUMS_OFFSET = prove
 (`!f:num->real^N l m n.
        (f sums l) (from m) /\ m < n
        ==> (f sums (l - vsum(m..(n-1)) f)) (from n)`,
 
 
let SUMS_OFFSET_REV = prove
 (`!f:num->real^N l m n.
        (f sums l) (from m) /\ n < m
        ==> (f sums (l + vsum(n..m-1) f)) (from n)`,
 
 
let SERIES_DROP_LE = prove
 (`!f g s a b.
        (f sums a) s /\ (g sums b) s /\
        (!x. x 
IN s ==> drop(f x) <= drop(g x))
        ==> drop a <= drop b`,
 
 
let SERIES_DROP_POS = prove
 (`!f s a.
        (f sums a) s /\ (!x. x 
IN s ==> &0 <= drop(f x))
        ==> &0 <= drop a`,
  REPEAT STRIP_TAC THEN
  MP_TAC(ISPECL [`(\n. vec 0):num->real^1`; `f:num->real^1`; `s:num->bool`;
                 `vec 0:real^1`; `a:real^1`] 
SERIES_DROP_LE) THEN
  ASM_SIMP_TAC[
SUMS_0; 
DROP_VEC]);;
 
 
let SERIES_BOUND = prove
 (`!f:num->real^N g s a b.
        (f sums a) s /\ ((lift o g) sums (lift b)) s /\
        (!i. i 
IN s ==> norm(f i) <= g i)
        ==> norm(a) <= b`,
 
 
(* ------------------------------------------------------------------------- *)
(* Similar combining theorems for infsum.                                    *)
(* ------------------------------------------------------------------------- *)
let INFSUM_ADD = prove
 (`!x y s. summable s x /\ summable s y
           ==> infsum s (\i. x i + y i) = infsum s x + infsum s y`,
 
 
let INFSUM_SUB = prove
 (`!x y s. summable s x /\ summable s y
           ==> infsum s (\i. x i - y i) = infsum s x - infsum s y`,
 
 
let INFSUM_EQ = prove
 (`!f g k. summable k f /\ summable k g /\ (!x. x 
IN k ==> f x = g x)
           ==> infsum k f = infsum k g`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[infsum] THEN
  AP_TERM_TAC THEN ABS_TAC THEN ASM_MESON_TAC[
SUMS_EQ; 
SUMS_INFSUM]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Cauchy criterion for series.                                              *)
(* ------------------------------------------------------------------------- *)
let SEQUENCE_CAUCHY_WLOG = prove
 (`!P s. (!m n:num. P m /\ P n ==> dist(s m,s n) < e) <=>
         (!m n. P m /\ P n /\ m <= n ==> dist(s m,s n) < e)`,
 
 
let SERIES_CAUCHY = prove
 (`!f s. (?l. (f sums l) s) =
         !e. &0 < e
             ==> ?N. !m n. m >= N
                           ==> norm(vsum(s 
INTER (m..n)) f) < e`,
  REPEAT GEN_TAC THEN REWRITE_TAC[sums; 
CONVERGENT_EQ_CAUCHY; cauchy] THEN
  REWRITE_TAC[
SEQUENCE_CAUCHY_WLOG] THEN ONCE_REWRITE_TAC[
DIST_SYM] THEN
  SIMP_TAC[dist; 
VSUM_DIFF_LEMMA; 
NORM_VSUM_TRIVIAL_LEMMA] THEN
  REWRITE_TAC[
GE; TAUT `a ==> b \/ c <=> a /\ ~b ==> c`] THEN
  REWRITE_TAC[
NOT_LT; ARITH_RULE
   `(N <= m /\ N <= n /\ m <= n) /\ m + 1 <= n <=>
    N + 1 <= m + 1 /\ m + 1 <= n`] THEN
  AP_TERM_TAC THEN REWRITE_TAC[
FUN_EQ_THM] THEN X_GEN_TAC `e:real` THEN
  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
  EQ_TAC THEN DISCH_THEN(X_CHOOSE_TAC `N:num`) THENL
   [EXISTS_TAC `N + 1`; EXISTS_TAC `N:num`] THEN
  REPEAT STRIP_TAC THEN
  ASM_SIMP_TAC[ARITH_RULE `N + 1 <= m + 1 ==> N <= m + 1`] THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`m - 1`; `n:num`]) THEN
  SUBGOAL_THEN `m - 1 + 1 = m` SUBST_ALL_TAC THENL
   [ALL_TAC; ANTS_TAC THEN SIMP_TAC[]] THEN
  ASM_ARITH_TAC);;
 
 
let SUMMABLE_IFF_EVENTUALLY = prove
 (`!f g k. (?N. !n. N <= n /\ n 
IN k ==> f n = g n)
           ==> (summable k f <=> summable k g)`,
  REWRITE_TAC[summable; 
SERIES_CAUCHY] THEN REPEAT GEN_TAC THEN
  DISCH_THEN(X_CHOOSE_THEN `N0:num` STRIP_ASSUME_TAC) THEN
  AP_TERM_TAC THEN REWRITE_TAC[
FUN_EQ_THM] THEN X_GEN_TAC `e:real` THEN
  AP_TERM_TAC THEN EQ_TAC THEN
  DISCH_THEN(X_CHOOSE_THEN `N1:num`
   (fun th -> EXISTS_TAC `N0 + N1:num` THEN MP_TAC th)) THEN
  REPEAT(MATCH_MP_TAC 
MONO_FORALL THEN GEN_TAC) THEN
  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
  (ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC]) THEN
  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
  MATCH_MP_TAC 
VSUM_EQ THEN ASM_SIMP_TAC[
IN_INTER; 
IN_NUMSEG] THEN
  REPEAT STRIP_TAC THENL [ALL_TAC; CONV_TAC SYM_CONV] THEN
  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
  ASM_ARITH_TAC);;
 
 
(* ------------------------------------------------------------------------- *)
(* Uniform vesion of Cauchy criterion.                                       *)
(* ------------------------------------------------------------------------- *)
let SERIES_CAUCHY_UNIFORM = prove
 (`!P f:A->num->real^N k.
        (?l. !e. &0 < e
                 ==> ?N. !n x. N <= n /\ P x
                               ==> dist(vsum(k 
INTER (0..n)) (f x),
                                        l x) < e) <=>
        (!e. &0 < e ==> ?N. !m n x. N <= m /\ P x
                                    ==> norm(vsum(k 
INTER (m..n)) (f x)) < e)`,
  REPEAT GEN_TAC THEN
  REWRITE_TAC[sums; 
UNIFORMLY_CONVERGENT_EQ_CAUCHY; cauchy] THEN
  ONCE_REWRITE_TAC[MESON[]
   `(!m n:num y. N <= m /\ N <= n /\ P y ==> Q m n y) <=>
    (!y. P y ==> !m n. N <= m /\ N <= n ==> Q m n y)`] THEN
  REWRITE_TAC[
SEQUENCE_CAUCHY_WLOG] THEN ONCE_REWRITE_TAC[
DIST_SYM] THEN
  SIMP_TAC[dist; 
VSUM_DIFF_LEMMA; 
NORM_VSUM_TRIVIAL_LEMMA] THEN
  REWRITE_TAC[
GE; TAUT `a ==> b \/ c <=> a /\ ~b ==> c`] THEN
  REWRITE_TAC[
NOT_LT; ARITH_RULE
   `(N <= m /\ N <= n /\ m <= n) /\ m + 1 <= n <=>
    N + 1 <= m + 1 /\ m + 1 <= n`] THEN
  AP_TERM_TAC THEN REWRITE_TAC[
FUN_EQ_THM] THEN X_GEN_TAC `e:real` THEN
  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
  EQ_TAC THEN DISCH_THEN(X_CHOOSE_TAC `N:num`) THENL
   [EXISTS_TAC `N + 1`; EXISTS_TAC `N:num`] THEN
  REPEAT STRIP_TAC THEN
  ASM_SIMP_TAC[ARITH_RULE `N + 1 <= m + 1 ==> N <= m + 1`] THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `x:A`) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(MP_TAC o SPECL [`m - 1`; `n:num`]) THEN
  SUBGOAL_THEN `m - 1 + 1 = m` SUBST_ALL_TAC THENL
   [ALL_TAC; ANTS_TAC THEN SIMP_TAC[]] THEN
  ASM_ARITH_TAC);;
 
 
(* ------------------------------------------------------------------------- *)
(* So trivially, terms of a convergent series go to zero.                    *)
(* ------------------------------------------------------------------------- *)
let SERIES_GOESTOZERO = prove
 (`!s x. summable s x
         ==> !e. &0 < e
                 ==> eventually (\n. n 
IN s ==> norm(x n) < e) sequentially`,
  REPEAT GEN_TAC THEN REWRITE_TAC[summable; 
SERIES_CAUCHY] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `e:real` THEN
  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[
EVENTUALLY_SEQUENTIALLY] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `N:num` THEN DISCH_TAC THEN
  X_GEN_TAC `n:num` THEN REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`n:num`; `n:num`]) THEN
  ASM_SIMP_TAC[
NUMSEG_SING; 
GE; SET_RULE `n 
IN s ==> s 
INTER {n} = {n}`] THEN
  REWRITE_TAC[
VSUM_SING]);;
 
 
let SUMMABLE_IMP_TOZERO = prove
 (`!f:num->real^N k.
       summable k f
       ==> ((\n. if n 
IN k then f(n) else vec 0) --> vec 0) sequentially`,
  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM 
SUMMABLE_RESTRICT] THEN
  REWRITE_TAC[summable; 
LIM_SEQUENTIALLY; 
INTER_UNIV; sums] THEN
  DISCH_THEN(X_CHOOSE_TAC `l:real^N`) THEN X_GEN_TAC `e:real` THEN
  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  ASM_REWRITE_TAC[
REAL_HALF; 
LEFT_IMP_EXISTS_THM] THEN
  X_GEN_TAC `N:num` THEN DISCH_TAC THEN EXISTS_TAC `N + 1` THEN
  X_GEN_TAC `n:num` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(fun th ->
    MP_TAC(SPEC `n - 1` th) THEN MP_TAC(SPEC `n:num` th)) THEN
  ASM_SIMP_TAC[ARITH_RULE `N + 1 <= n ==> N <= n /\ N <= n - 1`] THEN
  ABBREV_TAC `m = n - 1` THEN
  SUBGOAL_THEN `n = SUC m` SUBST1_TAC THENL
   [ASM_ARITH_TAC; ALL_TAC] THEN
  REWRITE_TAC[
VSUM_CLAUSES_NUMSEG; 
LE_0] THEN
  REWRITE_TAC[NORM_ARITH `dist(x,vec 0) = norm x`] THEN
  COND_CASES_TAC THEN ASM_REWRITE_TAC[
NORM_0] THEN CONV_TAC NORM_ARITH);;
 
 
(* ------------------------------------------------------------------------- *)
(* Comparison test.                                                          *)
(* ------------------------------------------------------------------------- *)
let SERIES_COMPARISON = prove
 (`!f g s. (?l. ((lift o g) sums l) s) /\
           (?N. !n. n >= N /\ n 
IN s ==> norm(f n) <= g n)
           ==> ?l:real^N. (f sums l) s`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
SERIES_CAUCHY] THEN
  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (X_CHOOSE_TAC `N1:num`)) THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `e:real` THEN
  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN
  EXISTS_TAC `N1 + N2:num` THEN
  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN DISCH_TAC THEN
  MATCH_MP_TAC 
REAL_LET_TRANS THEN
  EXISTS_TAC `norm (vsum (s 
INTER (m .. n)) (lift o g))` THEN CONJ_TAC THENL
   [SIMP_TAC[GSYM 
LIFT_SUM; 
FINITE_INTER_NUMSEG; 
NORM_LIFT] THEN
    MATCH_MP_TAC(REAL_ARITH `x <= a ==> x <= abs(a)`) THEN
    MATCH_MP_TAC 
VSUM_NORM_LE THEN
    REWRITE_TAC[
FINITE_INTER_NUMSEG; 
IN_INTER; 
IN_NUMSEG] THEN
    ASM_MESON_TAC[ARITH_RULE `m >= N1 + N2:num /\ m <= x ==> x >= N1`];
    ASM_MESON_TAC[ARITH_RULE `m >= N1 + N2:num ==> m >= N2`]]);;
 
 
let SERIES_COMPARISON_BOUND = prove
 (`!f:num->real^N g s a.
        (g sums a) s /\ (!i. i 
IN s ==> norm(f i) <= drop(g i))
        ==> ?l. (f sums l) s /\ norm(l) <= drop a`,
  REPEAT STRIP_TAC THEN
  MP_TAC(ISPECL [`f:num->real^N`; `drop o (g:num->real^1)`; `s:num->bool`]
        
SUMMABLE_COMPARISON) THEN
  REWRITE_TAC[
o_DEF; 
LIFT_DROP; 
GE; ETA_AX; summable] THEN
  ANTS_TAC THENL [ASM_MESON_TAC[]; MATCH_MP_TAC 
MONO_EXISTS] THEN
  X_GEN_TAC `l:real^N` THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
  RULE_ASSUM_TAC(REWRITE_RULE[
FROM_0; 
INTER_UNIV; sums]) THEN
  MATCH_MP_TAC 
SERIES_BOUND THEN MAP_EVERY EXISTS_TAC
   [`f:num->real^N`; `drop o (g:num->real^1)`; `s:num->bool`] THEN
  ASM_REWRITE_TAC[sums; 
o_DEF; 
LIFT_DROP; ETA_AX]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Uniform version of comparison test.                                       *)
(* ------------------------------------------------------------------------- *)
let SERIES_COMPARISON_UNIFORM = prove
 (`!f g P s. (?l. ((lift o g) sums l) s) /\
             (?N. !n x. N <= n /\ n 
IN s /\ P x ==> norm(f x n) <= g n)
             ==> ?l:A->real^N.
                    !e. &0 < e
                        ==> ?N. !n x. N <= n /\ P x
                                      ==> dist(vsum(s 
INTER (0..n)) (f x),
                                               l x) < e`,
  REPEAT GEN_TAC THEN SIMP_TAC[
GE; 
SERIES_CAUCHY; 
SERIES_CAUCHY_UNIFORM] THEN
  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (X_CHOOSE_TAC `N1:num`)) THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `e:real` THEN
  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN
  EXISTS_TAC `N1 + N2:num` THEN
  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`; `x:A`] THEN DISCH_TAC THEN
  MATCH_MP_TAC 
REAL_LET_TRANS THEN
  EXISTS_TAC `norm (vsum (s 
INTER (m .. n)) (lift o g))` THEN CONJ_TAC THENL
   [SIMP_TAC[GSYM 
LIFT_SUM; 
FINITE_INTER_NUMSEG; 
NORM_LIFT] THEN
    MATCH_MP_TAC(REAL_ARITH `x <= a ==> x <= abs(a)`) THEN
    MATCH_MP_TAC 
VSUM_NORM_LE THEN
    REWRITE_TAC[
FINITE_INTER_NUMSEG; 
IN_INTER; 
IN_NUMSEG] THEN
    ASM_MESON_TAC[ARITH_RULE `N1 + N2:num <= m /\ m <= x ==> N1 <= x`];
    ASM_MESON_TAC[ARITH_RULE `N1 + N2:num <= m ==> N2 <= m`]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Ratio test.                                                               *)
(* ------------------------------------------------------------------------- *)
let SERIES_RATIO = prove
 (`!c a s N.
      c < &1 /\
      (!n. n >= N ==> norm(a(SUC n)) <= c * norm(a(n)))
      ==> ?l:real^N. (a sums l) s`,
 
 
(* ------------------------------------------------------------------------- *)
(* Ostensibly weaker versions of the boundedness of partial sums.            *)
(* ------------------------------------------------------------------------- *)
let BOUNDED_PARTIAL_SUMS = prove
 (`!f:num->real^N k.
        bounded { vsum(k..n) f | n 
IN (:num) }
        ==> bounded { vsum(m..n) f | m 
IN (:num) /\ n 
IN (:num) }`,
  REPEAT STRIP_TAC THEN
  SUBGOAL_THEN `bounded { vsum(0..n) f:real^N | n 
IN (:num) }` MP_TAC THENL
   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
BOUNDED_POS]) THEN
    REWRITE_TAC[bounded] THEN
    REWRITE_TAC[
SIMPLE_IMAGE; 
FORALL_IN_IMAGE; 
IN_UNIV] THEN
    DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `sum { i:num | i < k} (\i. norm(f i:real^N)) + B` THEN
    X_GEN_TAC `i:num` THEN ASM_CASES_TAC `i:num < k` THENL
     [MATCH_MP_TAC(REAL_ARITH
       `!y. x <= y /\ y <= a /\ &0 < b ==> x <= a + b`) THEN
      EXISTS_TAC `sum (0..i) (\i. norm(f i:real^N))` THEN
      ASM_SIMP_TAC[
VSUM_NORM; 
FINITE_NUMSEG] THEN
      MATCH_MP_TAC 
SUM_SUBSET THEN
      REWRITE_TAC[
FINITE_NUMSEG; 
FINITE_NUMSEG_LT; 
NORM_POS_LE] THEN
      REWRITE_TAC[
IN_DIFF; 
IN_NUMSEG; 
IN_ELIM_THM] THEN ASM_ARITH_TAC;
      ALL_TAC] THEN
    ASM_CASES_TAC `k = 0` THENL
     [FIRST_X_ASSUM SUBST_ALL_TAC THEN MATCH_MP_TAC(REAL_ARITH
       `x <= B /\ &0 <= b ==> x <= b + B`) THEN
      ASM_SIMP_TAC[
SUM_POS_LE; 
FINITE_NUMSEG_LT; 
NORM_POS_LE];
      ALL_TAC] THEN
    MP_TAC(ISPECL [`f:num->real^N`; `0`; `k:num`; `i:num`]
      
VSUM_COMBINE_L) THEN
    ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
    DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[
NUMSEG_LT] THEN
    MATCH_MP_TAC(NORM_ARITH
     `norm(x) <= a /\ norm(y) <= b ==> norm(x + y) <= a + b`) THEN
    ASM_SIMP_TAC[
VSUM_NORM; 
FINITE_NUMSEG];
    ALL_TAC] THEN
  DISCH_THEN(fun th ->
    MP_TAC(MATCH_MP 
BOUNDED_DIFFS (W CONJ th)) THEN MP_TAC th) THEN
  REWRITE_TAC[IMP_IMP; GSYM 
BOUNDED_UNION] THEN
  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b ==> c <=> b ==> a ==> c`]
        
BOUNDED_SUBSET) THEN
  REWRITE_TAC[
SUBSET; 
IN_ELIM_THM; 
IN_UNION; 
LEFT_IMP_EXISTS_THM; 
IN_UNIV] THEN
  MAP_EVERY X_GEN_TAC [`x:real^N`; `m:num`; `n:num`] THEN
  DISCH_THEN SUBST1_TAC THEN
  ASM_CASES_TAC `m = 0` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
  ASM_CASES_TAC `n:num < m` THENL
   [DISJ2_TAC THEN REPEAT(EXISTS_TAC `vsum(0..0) (f:num->real^N)`) THEN
    ASM_SIMP_TAC[
VSUM_TRIV_NUMSEG; 
VECTOR_SUB_REFL] THEN MESON_TAC[];
    ALL_TAC] THEN
  DISJ2_TAC THEN MAP_EVERY EXISTS_TAC
   [`vsum(0..n) (f:num->real^N)`; `vsum(0..(m-1)) (f:num->real^N)`] THEN
  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
  MP_TAC(ISPECL [`f:num->real^N`; `0`; `m:num`; `n:num`]
      
VSUM_COMBINE_L) THEN
  ANTS_TAC THENL [ASM_ARITH_TAC; VECTOR_ARITH_TAC]);;
 
 
(* ------------------------------------------------------------------------- *)
(* General Dirichlet convergence test (could make this uniform on a set).    *)
(* ------------------------------------------------------------------------- *)
let SUMMABLE_BILINEAR_PARTIAL_PRE = prove
 (`!f g h:real^M->real^N->real^P l k.
        bilinear h /\
        ((\n. h (f(n + 1)) (g(n))) --> l) sequentially /\
        summable (from k) (\n. h (f(n + 1) - f(n)) (g(n)))
        ==> summable (from k) (\n. h (f n) (g(n) - g(n - 1)))`,
  REPEAT GEN_TAC THEN
  REWRITE_TAC[summable; sums; 
FROM_INTER_NUMSEG] THEN
  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  FIRST_ASSUM(fun th ->
   REWRITE_TAC[MATCH_MP 
BILINEAR_VSUM_PARTIAL_PRE th]) THEN
  DISCH_THEN(X_CHOOSE_TAC `l':real^P`) THEN
  EXISTS_TAC `l - (h:real^M->real^N->real^P) (f k) (g(k - 1)) - l'` THEN
  REWRITE_TAC[
LIM_CASES_SEQUENTIALLY] THEN
  REPEAT(MATCH_MP_TAC 
LIM_SUB THEN ASM_REWRITE_TAC[
LIM_CONST]));;
 
 
let SERIES_DIRICHLET_BILINEAR = prove
 (`!f g h:real^M->real^N->real^P k m p l.
        bilinear h /\
        bounded { vsum (m..n) f | n 
IN (:num)} /\
        summable (from p) (\n. lift(norm(g(n + 1) - g(n)))) /\
        ((\n. h (g(n + 1)) (vsum(1..n) f)) --> l) sequentially
        ==> summable (from k) (\n. h (g n) (f n))`,
 
 
let SERIES_DIRICHLET = prove
 (`!f:num->real^N g N k m.
        bounded { vsum (m..n) f | n 
IN (:num)} /\
        (!n. N <= n ==> g(n + 1) <= g(n)) /\
        ((lift o g) --> vec 0) sequentially
        ==> summable (from k) (\n. g(n) % f(n))`,
 
 
(* ------------------------------------------------------------------------- *)
(* Rearranging absolutely convergent series.                                 *)
(* ------------------------------------------------------------------------- *)
let SERIES_REARRANGE_EQ = prove
 (`!x:num->real^N s p l.
        summable s (\n. lift(norm(x n))) /\ p permutes s
        ==> (((x o p) sums l) s <=> (x sums l) s)`,
 
 
let SERIES_REARRANGE = prove
 (`!x:num->real^N s p l.
        summable s (\n. lift(norm(x n))) /\ p permutes s /\ (x sums l) s
        ==> ((x o p) sums l) s`,
 
 
(* ------------------------------------------------------------------------- *)
(* Banach fixed point theorem (not really topological...)                    *)
(* ------------------------------------------------------------------------- *)
let BANACH_FIX = prove
 (`!f s c. complete s /\ ~(s = {}) /\
           &0 <= c /\ c < &1 /\
           (
IMAGE f s) 
SUBSET s /\
           (!x y. x 
IN s /\ y 
IN s ==> dist(f(x),f(y)) <= c * dist(x,y))
           ==> ?!x:real^N. x 
IN s /\ (f x = x)`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[
EXISTS_UNIQUE_THM] THEN CONJ_TAC THENL
   [ALL_TAC;
    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
    SUBGOAL_THEN `dist((f:real^N->real^N) x,f y) <= c * dist(x,y)` MP_TAC THENL
     [ASM_MESON_TAC[]; ALL_TAC] THEN
    ASM_REWRITE_TAC[REAL_ARITH `a <= c * a <=> &0 <= --a * (&1 - c)`] THEN
    ASM_SIMP_TAC[GSYM 
REAL_LE_LDIV_EQ; 
REAL_SUB_LT; 
real_div] THEN
    REWRITE_TAC[
REAL_MUL_LZERO; REAL_ARITH `&0 <= --x <=> ~(&0 < x)`] THEN
    MESON_TAC[
DIST_POS_LT]] THEN
  STRIP_ASSUME_TAC(prove_recursive_functions_exist num_RECURSION
    `(z 0 = @x:real^N. x 
IN s) /\ (!n. z(SUC n) = f(z n))`) THEN
  SUBGOAL_THEN `!n. (z:num->real^N) n 
IN s` ASSUME_TAC THENL
   [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN
    ASM_MESON_TAC[
MEMBER_NOT_EMPTY; 
SUBSET; 
IN_IMAGE];
    ALL_TAC] THEN
  UNDISCH_THEN `z 0 = @x:real^N. x 
IN s` (K ALL_TAC) THEN
  SUBGOAL_THEN `?x:real^N. x 
IN s /\ (z --> x) sequentially` MP_TAC THENL
   [ALL_TAC;
    MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
    ABBREV_TAC `e = dist(f(a:real^N),a)` THEN
    SUBGOAL_THEN `~(&0 < e)` (fun th -> ASM_MESON_TAC[th; 
DIST_POS_LT]) THEN
    DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
LIM_SEQUENTIALLY]) THEN
    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
    ASM_REWRITE_TAC[
REAL_HALF] THEN DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN
    SUBGOAL_THEN
     `dist(f(z N),a:real^N) < e / &2 /\ dist(f(z(N:num)),f(a)) < e / &2`
     (fun th -> ASM_MESON_TAC[th; 
DIST_TRIANGLE_HALF_R; 
REAL_LT_REFL]) THEN
    CONJ_TAC THENL [ASM_MESON_TAC[ARITH_RULE `N <= SUC N`]; ALL_TAC] THEN
    MATCH_MP_TAC 
REAL_LET_TRANS THEN
    EXISTS_TAC `c * dist((z:num->real^N) N,a)` THEN ASM_SIMP_TAC[] THEN
    MATCH_MP_TAC(REAL_ARITH `x < y /\ c * x <= &1 * x ==> c * x < y`) THEN
    ASM_SIMP_TAC[
LE_REFL; 
REAL_LE_RMUL; 
DIST_POS_LE; 
REAL_LT_IMP_LE]] THEN
  FIRST_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [complete]) THEN
  ASM_REWRITE_TAC[
CAUCHY] THEN
  SUBGOAL_THEN `!n. dist(z(n):real^N,z(SUC n)) <= c pow n * dist(z(0),z(1))`
  ASSUME_TAC THENL
   [INDUCT_TAC THEN
    REWRITE_TAC[
real_pow; ARITH; REAL_MUL_LID; 
REAL_LE_REFL] THEN
    MATCH_MP_TAC 
REAL_LE_TRANS THEN
    EXISTS_TAC `c * dist(z(n):real^N,z(SUC n))` THEN
    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
    REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN ASM_SIMP_TAC[
REAL_LE_LMUL];
    ALL_TAC] THEN
  SUBGOAL_THEN
   `!m n:num. (&1 - c) * dist(z(m):real^N,z(m+n))
                <= c pow m * dist(z(0),z(1)) * (&1 - c pow n)`
  ASSUME_TAC THENL
   [GEN_TAC THEN INDUCT_TAC THENL
     [REWRITE_TAC[
ADD_CLAUSES; 
DIST_REFL; 
REAL_MUL_RZERO] THEN
      MATCH_MP_TAC 
REAL_LE_MUL THEN
      ASM_SIMP_TAC[
REAL_LE_MUL; 
REAL_POW_LE; 
DIST_POS_LE; 
REAL_SUB_LE;
                   
REAL_POW_1_LE; 
REAL_LT_IMP_LE];
      ALL_TAC] THEN
    MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC
    `(&1 - c) * (dist(z m:real^N,z(m + n)) + dist(z(m + n),z(m + SUC n)))` THEN
    ASM_SIMP_TAC[
REAL_LE_LMUL; 
REAL_SUB_LE; 
REAL_LT_IMP_LE; 
DIST_TRIANGLE] THEN
    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
      `c * x <= y ==> c * x' + y <= y' ==> c * (x + x') <= y'`)) THEN
    REWRITE_TAC[REAL_ARITH
     `q + a * b * (&1 - x) <= a * b * (&1 - y) <=> q <= a * b * (x - y)`] THEN
    REWRITE_TAC[
ADD_CLAUSES; 
real_pow] THEN
    REWRITE_TAC[REAL_ARITH `a * b * (d - c * d) = (&1 - c) * a * d * b`] THEN
    MATCH_MP_TAC 
REAL_LE_LMUL THEN
    ASM_SIMP_TAC[
REAL_SUB_LE; 
REAL_LT_IMP_LE] THEN
    REWRITE_TAC[GSYM 
REAL_POW_ADD; REAL_MUL_ASSOC] THEN ASM_MESON_TAC[];
    ALL_TAC] THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  ASM_CASES_TAC `(z:num->real^N) 0 = z 1` THENL
   [FIRST_X_ASSUM SUBST_ALL_TAC THEN EXISTS_TAC `0` THEN
    REWRITE_TAC[
GE; 
LE_0] THEN X_GEN_TAC `n:num` THEN
    FIRST_X_ASSUM(MP_TAC o SPECL [`0`; `n:num`]) THEN
    REWRITE_TAC[
ADD_CLAUSES; 
DIST_REFL; 
REAL_MUL_LZERO; 
REAL_MUL_RZERO] THEN
    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
    ASM_CASES_TAC `(z:num->real^N) 0 = z n` THEN
    ASM_REWRITE_TAC[
DIST_REFL; 
REAL_NOT_LE] THEN
    ASM_SIMP_TAC[
REAL_LT_MUL; 
DIST_POS_LT; 
REAL_SUB_LT];
    ALL_TAC] THEN
  MP_TAC(SPECL [`c:real`; `e * (&1 - c) / dist((z:num->real^N) 0,z 1)`]
   
REAL_ARCH_POW_INV) THEN
  ASM_SIMP_TAC[
REAL_LT_MUL; 
REAL_LT_DIV; 
REAL_SUB_LT; 
DIST_POS_LT] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
  REWRITE_TAC[
real_div; 
GE; REAL_MUL_ASSOC] THEN
  ASM_SIMP_TAC[
REAL_LT_RDIV_EQ; GSYM 
real_div; 
DIST_POS_LT] THEN
  ASM_SIMP_TAC[GSYM 
REAL_LT_LDIV_EQ; 
REAL_SUB_LT] THEN DISCH_TAC THEN
  REWRITE_TAC[
LE_EXISTS; 
LEFT_IMP_EXISTS_THM] THEN
  GEN_TAC THEN X_GEN_TAC `d:num` THEN DISCH_THEN SUBST_ALL_TAC THEN
  ONCE_REWRITE_TAC[
DIST_SYM] THEN
  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP(REAL_ARITH
    `d < e ==> x <= d ==> x < e`)) THEN
  ASM_SIMP_TAC[
REAL_LE_RDIV_EQ; 
REAL_SUB_LT] THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`N:num`; `d:num`]) THEN
  MATCH_MP_TAC(REAL_ARITH
  `(c * d) * e <= (c * d) * &1 ==> x * y <= c * d * e ==> y * x <= c * d`) THEN
  MATCH_MP_TAC 
REAL_LE_LMUL THEN
  ASM_SIMP_TAC[
REAL_LE_MUL; 
REAL_POW_LE; 
DIST_POS_LE; REAL_ARITH
   `&0 <= x ==> &1 - x <= &1`]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Edelstein fixed point theorem.                                            *)
(* ------------------------------------------------------------------------- *)
let EDELSTEIN_FIX = prove
 (`!f s. compact s /\ ~(s = {}) /\ (
IMAGE f s) 
SUBSET s /\
         (!x y. x 
IN s /\ y 
IN s /\ ~(x = y) ==> dist(f(x),f(y)) < dist(x,y))
         ==> ?!x:real^N. x 
IN s /\ f x = x`,
  MAP_EVERY X_GEN_TAC [`g:real^N->real^N`; `s:real^N->bool`] THEN
  REPEAT STRIP_TAC THEN REWRITE_TAC[
EXISTS_UNIQUE_THM] THEN CONJ_TAC THENL
   [ALL_TAC; ASM_MESON_TAC[
REAL_LT_REFL]] THEN
  SUBGOAL_THEN
   `!x y. x 
IN s /\ y 
IN s ==> dist((g:real^N->real^N)(x),g(y)) <= dist(x,y)`
  ASSUME_TAC THENL
   [REPEAT STRIP_TAC THEN ASM_CASES_TAC `x:real^N = y` THEN
    ASM_SIMP_TAC[
DIST_REFL; 
REAL_LE_LT];
    ALL_TAC] THEN
  ASM_CASES_TAC `?x:real^N. x 
IN s /\ ~(g x = x)` THENL
   [ALL_TAC; ASM SET_TAC[]] THEN
  FIRST_X_ASSUM(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
  ABBREV_TAC `y = (g:real^N->real^N) x` THEN
  SUBGOAL_THEN `(y:real^N) 
IN s` ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
COMPACT_PCROSS o W CONJ) THEN
  REWRITE_TAC[compact; 
PCROSS] THEN
  (STRIP_ASSUME_TAC o prove_general_recursive_function_exists)
    `?f:num->real^N->real^N.
        (!z. f 0 z = z) /\ (!z n. f (SUC n) z = g(f n z))` THEN
  SUBGOAL_THEN `!n z. z 
IN s ==> (f:num->real^N->real^N) n z 
IN s`
  STRIP_ASSUME_TAC THENL [INDUCT_TAC THEN ASM SET_TAC[]; ALL_TAC] THEN
  SUBGOAL_THEN
   `!m n w z. m <= n /\ w 
IN s /\ z 
IN s
              ==> dist((f:num->real^N->real^N) n w,f n z) <= dist(f m w,f m z)`
  ASSUME_TAC THENL
   [REWRITE_TAC[
RIGHT_FORALL_IMP_THM; 
IMP_CONJ] THEN
    MATCH_MP_TAC 
TRANSITIVE_STEPWISE_LE THEN
    RULE_ASSUM_TAC(REWRITE_RULE[
SUBSET; 
FORALL_IN_IMAGE]) THEN
    ASM_SIMP_TAC[
REAL_LE_REFL] THEN MESON_TAC[
REAL_LE_TRANS];
    ALL_TAC] THEN
  DISCH_THEN(MP_TAC o SPEC
   `\n:num. pastecart (f n (x:real^N)) (f n y:real^N)`) THEN
  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[
LEFT_IMP_EXISTS_THM]] THEN
  MAP_EVERY X_GEN_TAC [`l:real^(N,N)finite_sum`; `s:num->num`] THEN
  REWRITE_TAC[
o_DEF; 
IN_ELIM_THM] THEN
  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
  REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC SUBST_ALL_TAC) THEN
  SUBGOAL_THEN
   `(\x:real^(N,N)finite_sum. fstcart x) 
continuous_on UNIV /\
    (\x:real^(N,N)finite_sum. sndcart x) 
continuous_on UNIV`
  MP_TAC THENL
   [CONJ_TAC THEN MATCH_MP_TAC 
LINEAR_CONTINUOUS_ON THEN
    REWRITE_TAC[ETA_AX; 
LINEAR_FSTCART; 
LINEAR_SNDCART];
    ALL_TAC] THEN
  REWRITE_TAC[
CONTINUOUS_ON_SEQUENTIALLY; 
IN_UNIV] THEN
  DISCH_THEN(CONJUNCTS_THEN(fun th -> FIRST_ASSUM(MP_TAC o MATCH_MP th))) THEN
  REWRITE_TAC[
o_DEF; 
FSTCART_PASTECART; 
SNDCART_PASTECART; IMP_IMP] THEN
  ONCE_REWRITE_TAC[
CONJ_SYM] THEN
  DISCH_THEN(fun th -> CONJUNCTS_THEN2 (LABEL_TAC "A") (LABEL_TAC "B") th THEN
    MP_TAC(MATCH_MP 
LIM_SUB th)) THEN
  REWRITE_TAC[] THEN DISCH_THEN(LABEL_TAC "AB") THEN
  SUBGOAL_THEN
   `!n. dist(a:real^N,b) <= dist((f:num->real^N->real^N) n x,f n y)`
  STRIP_ASSUME_TAC THENL
   [X_GEN_TAC `N:num` THEN REWRITE_TAC[GSYM 
REAL_NOT_LT] THEN
    ONCE_REWRITE_TAC[GSYM 
REAL_SUB_LT] THEN DISCH_TAC THEN
    USE_THEN "AB" (MP_TAC o REWRITE_RULE[
LIM_SEQUENTIALLY]) THEN
    DISCH_THEN(fun th -> FIRST_X_ASSUM(MP_TAC o MATCH_MP th)) THEN
    REWRITE_TAC[
NOT_EXISTS_THM] THEN X_GEN_TAC `M:num` THEN
    DISCH_THEN(MP_TAC o SPEC `M + N:num`) THEN REWRITE_TAC[
LE_ADD] THEN
    MATCH_MP_TAC(NORM_ARITH
     `dist(fx,fy) <= dist(x,y)
      ==> ~(dist(fx - fy,a - b) < dist(a,b) - dist(x,y))`) THEN
    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `M + N:num` o MATCH_MP 
MONOTONE_BIGGER) THEN
    ARITH_TAC;
    ALL_TAC] THEN
  SUBGOAL_THEN `b:real^N = a` SUBST_ALL_TAC THENL
   [MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
    ABBREV_TAC `e = dist(a,b) - dist((g:real^N->real^N) a,g b)` THEN
    SUBGOAL_THEN `&0 < e` ASSUME_TAC THENL
     [ASM_MESON_TAC[
REAL_SUB_LT]; ALL_TAC] THEN
    SUBGOAL_THEN
     `?n. dist((f:num->real^N->real^N) n x,a) < e / &2 /\
          dist(f n y,b) < e / &2`
    STRIP_ASSUME_TAC THENL
     [MAP_EVERY (fun s -> USE_THEN s (MP_TAC o SPEC `e / &2` o
        REWRITE_RULE[
LIM_SEQUENTIALLY])) ["A";
 
  "B"] THEN
      ASM_REWRITE_TAC[REAL_HALF] THEN
      DISCH_THEN(X_CHOOSE_TAC `M:num`) THEN
      DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN
      EXISTS_TAC `(s:num->num) (M + N)` THEN
      CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC;
      ALL_TAC] THEN
    SUBGOAL_THEN `dist(f (SUC n) x,(g:real^N->real^N) a) +
                  dist((f:num->real^N->real^N) (SUC n) y,g b) < e`
    MP_TAC THENL
     [ASM_REWRITE_TAC[] THEN
      MATCH_MP_TAC(REAL_ARITH `x < e / &2 /\ y < e / &2 ==> x + y < e`) THEN
      CONJ_TAC THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
       `dist(x,y) < e
        ==> dist(g x,g y) <= dist(x,y) ==> dist(g x,g y) < e`)) THEN
      ASM_SIMP_TAC[];
      ALL_TAC] THEN
    MP_TAC(SPEC `SUC n` (ASSUME
    `!n. dist (a:real^N,b) <=
         dist ((f:num->real^N->real^N) n x,f n y)`)) THEN
    EXPAND_TAC "e" THEN NORM_ARITH_TAC;
    ALL_TAC] THEN
  EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN
  EXISTS_TAC `\n:num. (f:num->real^N->real^N) (SUC(s n)) x` THEN
  REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN CONJ_TAC THENL
   [ASM_REWRITE_TAC[] THEN
    SUBGOAL_THEN `(g:real^N->real^N) continuous_on s` MP_TAC THENL
     [REWRITE_TAC[continuous_on] THEN ASM_MESON_TAC[REAL_LET_TRANS];
      ALL_TAC] THEN
    REWRITE_TAC[CONTINUOUS_ON_SEQUENTIALLY; o_DEF] THEN
    DISCH_THEN MATCH_MP_TAC THEN ASM_SIMP_TAC[];
    SUBGOAL_THEN `!n. (f:num->real^N->real^N) (SUC n) x = f n y`
     (fun th -> ASM_SIMP_TAC[th]) THEN
    INDUCT_TAC THEN ASM_REWRITE_TAC[]]);;
(* ------------------------------------------------------------------------- *)
(* Dini's theorem.                                                           *)
(* ------------------------------------------------------------------------- *)
let DINI = prove
 (`!f:num->real^N->real^1 g s.
        compact s /\ (!n. (f n) 
continuous_on s) /\ g 
continuous_on s /\
        (!x. x 
IN s ==> ((\n. (f n x)) --> g x) sequentially) /\
        (!n x. x 
IN s ==> drop(f n x) <= drop(f (n + 1) x))
        ==> !e. &0 < e
                ==> eventually (\n. !x. x 
IN s ==> norm(f n x - g x) < e)
                               sequentially`,
 
 
(* ------------------------------------------------------------------------- *)
(* Closest point of a (closed) set to a point.                               *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* More general infimum of distance between two sets.                        *)
(* ------------------------------------------------------------------------- *)
let SETDIST_EMPTY = prove
 (`(!t. setdist({},t) = &0) /\ (!s. setdist(s,{}) = &0)`,
  REWRITE_TAC[setdist]);;
 
 
let REAL_LE_SETDIST = prove
  (`!s t:real^N->bool d.
        ~(s = {}) /\ ~(t = {}) /\
        (!x y. x 
IN s /\ y 
IN t ==> d <= dist(x,y))
        ==> d <= setdist(s,t)`,
  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[setdist] THEN
  MP_TAC(ISPEC `{dist(x:real^N,y) | x 
IN s /\ y 
IN t}` 
INF) THEN
  REWRITE_TAC[
FORALL_IN_GSPEC] THEN ANTS_TAC THENL
   [CONJ_TAC THENL [ASM SET_TAC[]; MESON_TAC[
DIST_POS_LE]]; ALL_TAC] THEN
  ASM_MESON_TAC[]);;
 
 
let SETDIST_LE_DIST = prove
 (`!s t x y:real^N. x 
IN s /\ y 
IN t ==> setdist(s,t) <= dist(x,y)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[setdist] THEN
  COND_CASES_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
  MP_TAC(ISPEC `{dist(x:real^N,y) | x 
IN s /\ y 
IN t}` 
INF) THEN
  REWRITE_TAC[
FORALL_IN_GSPEC] THEN ANTS_TAC THENL
   [CONJ_TAC THENL [ASM SET_TAC[]; MESON_TAC[
DIST_POS_LE]]; ALL_TAC] THEN
  ASM_MESON_TAC[]);;
 
 
let REAL_LE_SETDIST_EQ = prove
 (`!d s t:real^N->bool.
        d <= setdist(s,t) <=>
        (!x y. x 
IN s /\ y 
IN t ==> d <= dist(x,y)) /\
        (s = {} \/ t = {} ==> d <= &0)`,
 
 
let SETDIST_CLOSURE = prove
 (`(!s t:real^N->bool. setdist(closure s,t) = setdist(s,t)) /\
   (!s t:real^N->bool. setdist(s,closure t) = setdist(s,t))`,
 
 
let SETDIST_TRANSLATION = prove
 (`!a:real^N s t.
        setdist(
IMAGE (\x. a + x) s,
IMAGE (\x. a + x) t) = setdist(s,t)`,
  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[
SETDIST_DIFFERENCES] THEN
  AP_TERM_TAC THEN AP_TERM_TAC THEN
  REWRITE_TAC[SET_RULE
   `{f x y | x 
IN IMAGE g s /\ y 
IN IMAGE g t} =
    {f (g x) (g y) | x 
IN s /\ y 
IN t}`] THEN
  REWRITE_TAC[VECTOR_ARITH `(a + x) - (a + y):real^N = x - y`]);;
 
 
add_translation_invariants [SETDIST_TRANSLATION];;
let SETDIST_LINEAR_IMAGE = prove
 (`!f:real^M->real^N s t.
        linear f /\ (!x. norm(f x) = norm x)
        ==> setdist(
IMAGE f s,
IMAGE f t) = setdist(s,t)`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[setdist; 
IMAGE_EQ_EMPTY] THEN
  COND_CASES_TAC THEN ASM_REWRITE_TAC[dist] THEN AP_TERM_TAC THEN
  REWRITE_TAC[SET_RULE
   `{f x y | x 
IN IMAGE g s /\ y 
IN IMAGE g t} =
    {f (g x) (g y) | x 
IN s /\ y 
IN t}`] THEN
  FIRST_X_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP 
LINEAR_SUB th)]) THEN
  ASM_REWRITE_TAC[]);;
 
 
add_linear_invariants [SETDIST_LINEAR_IMAGE];;
let SETDIST_UNIQUE = prove
 (`!s t a b:real^N d.
        a 
IN s /\ b 
IN t /\ dist(a,b) = d /\
        (!x y. x 
IN s /\ y 
IN t ==> dist(a,b) <= dist(x,y))
        ==> setdist(s,t) = d`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL
   [ASM_MESON_TAC[
SETDIST_LE_DIST];
    MATCH_MP_TAC 
REAL_LE_SETDIST THEN ASM SET_TAC[]]);;
 
 
let SETDIST_EQ_0_SING = prove
 (`(!s x:real^N. setdist({x},s) = &0 <=> s = {} \/ x 
IN closure s) /\
   (!s x:real^N. setdist(s,{x}) = &0 <=> s = {} \/ x 
IN closure s)`,
 
 
let SETDIST_BALLS = prove
 (`(!a b:real^N r s.
        setdist(ball(a,r),ball(b,s)) =
        if r <= &0 \/ s <= &0 then &0 else max (&0) (dist(a,b) - (r + s))) /\
   (!a b:real^N r s.
        setdist(ball(a,r),cball(b,s)) =
        if r <= &0 \/ s < &0 then &0 else max (&0) (dist(a,b) - (r + s))) /\
   (!a b:real^N r s.
        setdist(cball(a,r),ball(b,s)) =
        if r < &0 \/ s <= &0 then &0 else max (&0) (dist(a,b) - (r + s))) /\
   (!a b:real^N r s.
        setdist(cball(a,r),cball(b,s)) =
        if r < &0 \/ s < &0 then &0 else max (&0) (dist(a,b) - (r + s)))`,
 
 
(* ------------------------------------------------------------------------- *)
(* Use set distance for an easy proof of separation properties etc.          *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Hausdorff distance between sets.                                          *)
(* ------------------------------------------------------------------------- *)
let hausdist = new_definition
 `hausdist(s:real^N->bool,t:real^N->bool) =
        let ds = {setdist({x},t) | x IN s} UNION {setdist({y},s) | y IN t} in
        if ~(ds = {}) /\ (?b. !d. d IN ds ==> d <= b) then sup ds
        else &0`;; 
let HAUSDIST_EMPTY = prove
 (`(!t:real^N->bool. hausdist ({},t) = &0) /\
   (!s:real^N->bool. hausdist (s,{}) = &0)`,
  REWRITE_TAC[hausdist; 
LET_DEF; 
LET_END_DEF; 
SETDIST_EMPTY] THEN
  REWRITE_TAC[SET_RULE `{f x | x 
IN {}} = {}`; 
UNION_EMPTY] THEN
  REWRITE_TAC[SET_RULE `{c |x| x 
IN s} = {} <=> s = {}`] THEN
  X_GEN_TAC `s:real^N->bool` THEN
  ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_REWRITE_TAC[] THEN
  ASM_SIMP_TAC[SET_RULE `~(s = {}) ==> {c |x| x 
IN s} = {c}`] THEN
  REWRITE_TAC[
SUP_SING; 
COND_ID]);;
 
 
let HAUSDIST_EQ = prove
 (`!s t:real^M->bool s' t':real^N->bool.
        (!b. (!x. x 
IN s ==> setdist({x},t) <= b) /\
             (!y. y 
IN t ==> setdist({y},s) <= b) <=>
             (!x. x 
IN s' ==> setdist({x},t') <= b) /\
             (!y. y 
IN t' ==> setdist({y},s') <= b))
        ==> hausdist(s,t) = hausdist(s',t')`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[hausdist; 
LET_DEF; 
LET_END_DEF] THEN
  MATCH_MP_TAC(MESON[]
   `(p <=> p') /\ s = s'
    ==> (if p then s else &0) = (if p' then s' else &0)`) THEN
  CONJ_TAC THENL
   [BINOP_TAC THENL
     [PURE_REWRITE_TAC[SET_RULE `s = {} <=> !x. x 
IN s ==> F`];
      AP_TERM_TAC THEN ABS_TAC];
    MATCH_MP_TAC 
SUP_EQ] THEN
  PURE_REWRITE_TAC[
FORALL_IN_UNION; 
FORALL_IN_GSPEC] THEN
  ASM_REWRITE_TAC[] THEN
  REWRITE_TAC[DE_MORGAN_THM; 
NOT_FORALL_THM; 
MEMBER_NOT_EMPTY] THEN
  REWRITE_TAC[GSYM DE_MORGAN_THM] THEN AP_TERM_TAC THEN EQ_TAC THEN
  DISCH_THEN(fun th -> POP_ASSUM MP_TAC THEN ASSUME_TAC th) THEN
  ASM_REWRITE_TAC[
NOT_IN_EMPTY] THEN
  DISCH_THEN(MP_TAC o SPEC `--(&1):real`) THEN
  SIMP_TAC[
SETDIST_POS_LE; REAL_ARITH `&0 <= x ==> ~(x <= --(&1))`] THEN
  SET_TAC[]);;
 
 
add_translation_invariants [HAUSDIST_TRANSLATION];;
let HAUSDIST_LINEAR_IMAGE = prove
 (`!f:real^M->real^N s t.
           linear f /\ (!x. norm(f x) = norm x)
           ==> hausdist(
IMAGE f s,
IMAGE f t) = hausdist(s,t)`,
  REPEAT STRIP_TAC THEN
  REPEAT GEN_TAC THEN REWRITE_TAC[hausdist] THEN
  REWRITE_TAC[SET_RULE `{f x | x 
IN IMAGE g s} = {f(g x) | x 
IN s}`] THEN
  ONCE_REWRITE_TAC[SET_RULE `{(f:real^M->real^N) x} = 
IMAGE f {x}`] THEN
  ASM_SIMP_TAC[
SETDIST_LINEAR_IMAGE]);;
 
 
add_linear_invariants [HAUSDIST_LINEAR_IMAGE];;
let HAUSDIST_CLOSURE = prove
 (`(!s t:real^N->bool. hausdist(closure s,t) = hausdist(s,t)) /\
   (!s t:real^N->bool. hausdist(s,closure t) = hausdist(s,t))`,
 
 
let REAL_HAUSDIST_LE = prove
 (`!s t:real^N->bool b.
        ~(s = {}) /\ ~(t = {}) /\
        (!x. x 
IN s ==> setdist({x},t) <= b) /\
        (!y. y 
IN t ==> setdist({y},s) <= b)
        ==> hausdist(s,t) <= b`,
 
 
let REAL_LE_HAUSDIST  = prove
 (`!s t:real^N->bool a b c z.
        ~(s = {}) /\ ~(t = {}) /\
        (!x. x 
IN s ==> setdist({x},t) <= b) /\
        (!y. y 
IN t ==> setdist({y},s) <= c) /\
        (z 
IN s /\ a <= setdist({z},t) \/ z 
IN t /\ a <= setdist({z},s))
        ==> a <= hausdist(s,t)`,
 
 
let UPPER_LOWER_HEMICONTINUOUS = prove
 (`!f:real^M->real^N->bool t s.
      (!x. x 
IN s ==> f(x) 
SUBSET t) /\
      (!u. 
open_in (subtopology euclidean t) u
           ==> 
open_in (subtopology euclidean s)
                       {x | x 
IN s /\ f(x) 
SUBSET u}) /\
      (!u. 
closed_in (subtopology euclidean t) u
           ==> 
closed_in (subtopology euclidean s)
                         {x | x 
IN s /\ f(x) 
SUBSET u})
      ==> !x e. x 
IN s /\ &0 < e /\ bounded(f x)
                ==> ?d. &0 < d /\
                        !x'. x' 
IN s /\ dist(x,x') < d
                             ==> hausdist(f x,f x') < e`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN REPEAT STRIP_TAC THEN
  ASM_CASES_TAC `(f:real^M->real^N->bool) x = {}` THENL
   [ASM_REWRITE_TAC[
HAUSDIST_EMPTY] THEN MESON_TAC[
REAL_LT_01]; ALL_TAC] THEN
  FIRST_ASSUM(MP_TAC o SPECL [`x:real^M`; `e / &2`] o MATCH_MP
        
UPPER_LOWER_HEMICONTINUOUS_EXPLICIT) THEN
  ASM_REWRITE_TAC[
REAL_HALF] THEN
  DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
  FIRST_ASSUM(MP_TAC o SPEC `vec 0:real^N` o MATCH_MP 
BOUNDED_SUBSET_BALL) THEN
  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
  FIRST_ASSUM(MP_TAC o SPEC `t 
INTER ball(vec 0:real^N,r)` o
        CONJUNCT1 o CONJUNCT2) THEN
  SIMP_TAC[
OPEN_IN_OPEN_INTER; 
OPEN_BALL] THEN REWRITE_TAC[
open_in] THEN
  DISCH_THEN(MP_TAC o SPEC `x:real^M` o CONJUNCT2) THEN
  ASM_SIMP_TAC[
SUBSET_INTER; 
IN_ELIM_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `min d1 d2:real` THEN ASM_REWRITE_TAC[
REAL_LT_MIN] THEN
  X_GEN_TAC `x':real^M` THEN STRIP_TAC THEN
  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x':real^M`)) THEN
  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[
DIST_SYM] THEN ASM_REWRITE_TAC[] THEN
  STRIP_TAC THEN STRIP_TAC THEN
  ASM_CASES_TAC `(f:real^M->real^N->bool) x' = {}` THEN
  ASM_REWRITE_TAC[
HAUSDIST_EMPTY] THEN
  MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
REAL_HAUSDIST_LE THEN
  ASM_MESON_TAC[
SETDIST_LE_DIST; 
DIST_SYM; 
REAL_LE_TRANS;
                
IN_SING; 
REAL_LT_IMP_LE]);;
 
 
let HAUSDIST_NONTRIVIAL = prove
 (`!s t:real^N->bool.
        bounded s /\ bounded t /\ ~(s = {}) /\ ~(t = {})
        ==> hausdist(s,t) =
            sup({setdist ({x},t) | x 
IN s} 
UNION {setdist ({y},s) | y 
IN t})`,
 
 
let HAUSDIST_NONTRIVIAL_ALT = prove
 (`!s t:real^N->bool.
        bounded s /\ bounded t /\ ~(s = {}) /\ ~(t = {})
        ==> hausdist(s,t) = max (sup {setdist ({x},t) | x 
IN s})
                                (sup {setdist ({y},s) | y 
IN t})`,
 
 
let REAL_HAUSDIST_LE_EQ = prove
 (`!s t:real^N->bool b.
        ~(s = {}) /\ ~(t = {}) /\ bounded s /\ bounded t
        ==> (hausdist(s,t) <= b <=>
             (!x. x 
IN s ==> setdist({x},t) <= b) /\
             (!y. y 
IN t ==> setdist({y},s) <= b))`,
 
 
let HAUSDIST_TRANS = prove
 (`!s t u:real^N->bool.
        bounded s /\ bounded t /\ bounded u /\ ~(t = {})
        ==> hausdist(s,u) <= hausdist(s,t) + hausdist(t,u)`,
 
 
let HAUSDIST_EQ_0 = prove
 (`!s t:real^N->bool.
      bounded s /\ bounded t
      ==> (hausdist(s,t) = &0 <=> s = {} \/ t = {} \/ closure s = closure t)`,
 
 
let HAUSDIST_BALLS = prove
 (`(!a b:real^N r s.
        hausdist(ball(a,r),ball(b,s)) =
        if r <= &0 \/ s <= &0 then &0 else dist(a,b) + abs(r - s)) /\
   (!a b:real^N r s.
        hausdist(ball(a,r),cball(b,s)) =
        if r <= &0 \/ s < &0 then &0 else dist(a,b) + abs(r - s)) /\
   (!a b:real^N r s.
        hausdist(cball(a,r),ball(b,s)) =
        if r < &0 \/ s <= &0 then &0 else dist(a,b) + abs(r - s)) /\
   (!a b:real^N r s.
        hausdist(cball(a,r),cball(b,s)) =
        if r < &0 \/ s < &0 then &0 else dist(a,b) + abs(r - s))`,
 
 
let HAUSDIST_ALT = prove
 (`!s t:real^N->bool.
        bounded s /\ bounded t /\ ~(s = {}) /\ ~(t = {})
        ==> hausdist(s,t) =
            sup {abs(setdist({x},s) - setdist({x},t)) | x 
IN (:real^N)}`,
 
 
let CONTINUOUS_DIAMETER = prove
 (`!s:real^N->bool e.
        bounded s /\ ~(s = {}) /\ &0 < e
        ==> ?d. &0 < d /\
                !t. bounded t /\ ~(t = {}) /\ hausdist(s,t) < d
                    ==> abs(diameter s - diameter t) < e`,
 
 
(* ------------------------------------------------------------------------- *)
(* Isometries are embeddings, and even surjective in the compact case.       *)
(* ------------------------------------------------------------------------- *)
let ISOMETRY_IMP_OPEN_MAP = prove
 (`!f:real^M->real^N s t u.
        
IMAGE f s = t /\
        (!x y. x 
IN s /\ y 
IN s ==> dist(f x,f y) = dist(x,y)) /\
        
open_in (subtopology euclidean s) u
        ==> 
open_in (subtopology euclidean t) (
IMAGE f u)`,
  REWRITE_TAC[
open_in; 
FORALL_IN_IMAGE] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
  CONJ_TAC THENL [ASM SET_TAC[]; X_GEN_TAC `x:real^M` THEN DISCH_TAC] THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
  STRIP_TAC THEN ASM_REWRITE_TAC[
IMP_CONJ] THEN
  EXPAND_TAC "t" THEN REWRITE_TAC[
FORALL_IN_IMAGE] THEN
  RULE_ASSUM_TAC(REWRITE_RULE[
SUBSET]) THEN
  ASM_SIMP_TAC[
IN_IMAGE] THEN ASM_MESON_TAC[]);;
 
 
let ISOMETRY_IMP_HOMEOMORPHISM_COMPACT = prove
 (`!f s:real^N->bool.
        compact s /\ 
IMAGE f s 
SUBSET s /\
        (!x y. x 
IN s /\ y 
IN s ==> dist(f x,f y) = dist(x,y))
        ==> ?g. homeomorphism (s,s) (f,g)`,
  REPEAT STRIP_TAC THEN
  SUBGOAL_THEN `
IMAGE (f:real^N->real^N) s = s`
   (fun th -> ASM_MESON_TAC[th; 
ISOMETRY_IMP_EMBEDDING]) THEN
  FIRST_ASSUM(ASSUME_TAC o MATCH_MP 
ISOMETRY_ON_IMP_CONTINUOUS_ON) THEN
  ASM_REWRITE_TAC[GSYM 
SUBSET_ANTISYM_EQ] THEN REWRITE_TAC[
SUBSET] THEN
  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
  SUBGOAL_THEN `setdist({x},
IMAGE (f:real^N->real^N) s) = &0` MP_TAC THENL
   [MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ ~(&0 < x) ==> x = &0`) THEN
    REWRITE_TAC[
SETDIST_POS_LE] THEN DISCH_TAC THEN
    (X_CHOOSE_THEN `z:num->real^N` STRIP_ASSUME_TAC o
     prove_recursive_functions_exist num_RECURSION)
     `z 0 = (x:real^N) /\ !n. z(SUC n) = f(z n)` THEN
    SUBGOAL_THEN `!n. (z:num->real^N) n 
IN s` ASSUME_TAC THENL
     [INDUCT_TAC THEN ASM SET_TAC[]; ALL_TAC] THEN
    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [compact]) THEN
    DISCH_THEN(MP_TAC o SPEC `z:num->real^N`) THEN
    ASM_REWRITE_TAC[
NOT_EXISTS_THM] THEN
    MAP_EVERY X_GEN_TAC [`l:real^N`; `r:num->num`] THEN STRIP_TAC THEN
    FIRST_ASSUM(MP_TAC o MATCH_MP 
CONVERGENT_IMP_CAUCHY) THEN
    REWRITE_TAC[cauchy] THEN
    DISCH_THEN(MP_TAC o SPEC `setdist({x},
IMAGE (f:real^N->real^N) s)`) THEN
    ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `N:num`
     (MP_TAC o SPECL [`N:num`; `N + 1`])) THEN
    ANTS_TAC THENL [ARITH_TAC; REWRITE_TAC[
REAL_NOT_LT; 
o_THM]] THEN
    SUBGOAL_THEN `(r:num->num) N < r (N + 1)` MP_TAC THENL
     [FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC;
      REWRITE_TAC[
LT_EXISTS; 
LEFT_IMP_EXISTS_THM]] THEN
    X_GEN_TAC `d:num` THEN DISCH_THEN SUBST1_TAC THEN
    TRANS_TAC 
REAL_LE_TRANS `dist(x:real^N,z(SUC d))` THEN CONJ_TAC THENL
     [MATCH_MP_TAC 
SETDIST_LE_DIST THEN ASM SET_TAC[]; ALL_TAC] THEN
    MATCH_MP_TAC 
REAL_EQ_IMP_LE THEN
    SPEC_TAC(`(r:num->num) N`,`m:num`) THEN
    INDUCT_TAC THEN ASM_MESON_TAC[
ADD_CLAUSES];
    REWRITE_TAC[
SETDIST_EQ_0_SING; 
IMAGE_EQ_EMPTY] THEN
    ASM_MESON_TAC[
COMPACT_IMP_CLOSED; 
NOT_IN_EMPTY;
                  
COMPACT_CONTINUOUS_IMAGE; 
CLOSURE_CLOSED]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Urysohn's lemma (for real^N, where the proof is easy using distances).    *)
(* ------------------------------------------------------------------------- *)
let URYSOHN_LOCAL_STRONG = prove
 (`!s t u a b.
        
closed_in (subtopology euclidean u) s /\
        
closed_in (subtopology euclidean u) t /\
        s 
INTER t = {} /\ ~(a = b)
        ==> ?f:real^N->real^M.
               f 
continuous_on u /\
               (!x. x 
IN u ==> f(x) 
IN segment[a,b]) /\
               (!x. x 
IN u ==> (f x = a <=> x 
IN s)) /\
               (!x. x 
IN u ==> (f x = b <=> x 
IN t))`,
  let lemma = prove
   (`!s t u a b.
          closed_in (subtopology euclidean u) s /\
          closed_in (subtopology euclidean u) t /\
          s INTER t = {} /\ ~(s = {}) /\ ~(t = {}) /\ ~(a = b)
          ==> ?f:real^N->real^M.
                 f continuous_on u /\
                 (!x. x IN u ==> f(x) IN segment[a,b]) /\
                 (!x. x IN u ==> (f x = a <=> x IN s)) /\
                 (!x. x IN u ==> (f x = b <=> x IN t))`,
    REPEAT STRIP_TAC THEN EXISTS_TAC
      `\x:real^N. a + setdist({x},s) / (setdist({x},s) + setdist({x},t)) %
                      (b - a:real^M)` THEN REWRITE_TAC[] THEN
    SUBGOAL_THEN
     `(!x:real^N. x IN u ==> (setdist({x},s) = &0 <=> x IN s)) /\
      (!x:real^N. x IN u ==> (setdist({x},t) = &0 <=> x IN t))`
    STRIP_ASSUME_TAC THENL
     [ASM_REWRITE_TAC[SETDIST_EQ_0_SING] THEN CONJ_TAC THENL
       [MP_TAC(ISPEC `s:real^N->bool` CLOSED_IN_CLOSED);
        MP_TAC(ISPEC `t:real^N->bool` CLOSED_IN_CLOSED)] THEN
      DISCH_THEN(MP_TAC o SPEC `u:real^N->bool`) THEN
      ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool`
       (CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC)) THEN
      ASM_MESON_TAC[CLOSURE_CLOSED; INTER_SUBSET; SUBSET_CLOSURE; SUBSET;
                    IN_INTER; CLOSURE_SUBSET];
      ALL_TAC] THEN
    SUBGOAL_THEN `!x:real^N. x IN u ==> &0 < setdist({x},s) + setdist({x},t)`
    ASSUME_TAC THENL
     [REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
        `&0 <= x /\ &0 <= y /\ ~(x = &0 /\ y = &0) ==> &0 < x + y`) THEN
      REWRITE_TAC[SETDIST_POS_LE] THEN ASM SET_TAC[];
      ALL_TAC] THEN
    REPEAT CONJ_TAC THENL
     [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
      REWRITE_TAC[real_div; GSYM VECTOR_MUL_ASSOC] THEN
      REPEAT(MATCH_MP_TAC CONTINUOUS_ON_MUL THEN CONJ_TAC) THEN
      REWRITE_TAC[CONTINUOUS_ON_CONST; o_DEF] THEN
      REWRITE_TAC[CONTINUOUS_ON_LIFT_SETDIST] THEN
      MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
      ASM_SIMP_TAC[REAL_LT_IMP_NZ] THEN
      REWRITE_TAC[LIFT_ADD] THEN MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
      REWRITE_TAC[CONTINUOUS_ON_LIFT_SETDIST];
      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
      REWRITE_TAC[segment; IN_ELIM_THM] THEN
      REWRITE_TAC[VECTOR_MUL_EQ_0; LEFT_OR_DISTRIB; VECTOR_ARITH
       `a + x % (b - a):real^N = (&1 - u) % a + u % b <=>
        (x - u) % (b - a) = vec 0`;
       EXISTS_OR_THM] THEN
      DISJ1_TAC THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
      REWRITE_TAC[REAL_SUB_0; UNWIND_THM1] THEN
      ASM_SIMP_TAC[REAL_LE_DIV; REAL_LE_ADD; SETDIST_POS_LE; REAL_LE_LDIV_EQ;
                   REAL_ARITH `a <= &1 * (a + b) <=> &0 <= b`];
      REWRITE_TAC[VECTOR_ARITH `a + x:real^N = a <=> x = vec 0`];
      REWRITE_TAC[VECTOR_ARITH `a + x % (b - a):real^N = b <=>
                                (x - &1) % (b - a) = vec 0`]] THEN
    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN
    ASM_SIMP_TAC[REAL_SUB_0; REAL_EQ_LDIV_EQ;
                 REAL_MUL_LZERO; REAL_MUL_LID] THEN
    REWRITE_TAC[REAL_ARITH `x:real = x + y <=> y = &0`] THEN
    ASM_REWRITE_TAC[]) in
  MATCH_MP_TAC(MESON[]
   `(!s t. P s t <=> P t s) /\
    (!s t. ~(s = {}) /\ ~(t = {}) ==> P s t) /\
    P {} {} /\ (!t. ~(t = {}) ==> P {} t)
    ==> !s t. P s t`) THEN
  REPEAT CONJ_TAC THENL
   [REPEAT GEN_TAC THEN
    GEN_REWRITE_TAC (RAND_CONV o BINDER_CONV) [SWAP_FORALL_THM] THEN
    REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
    REWRITE_TAC[SEGMENT_SYM; INTER_COMM; CONJ_ACI; EQ_SYM_EQ];
    SIMP_TAC[lemma];
    REPEAT STRIP_TAC THEN EXISTS_TAC `(\x. midpoint(a,b)):real^N->real^M` THEN
    ASM_SIMP_TAC[NOT_IN_EMPTY; CONTINUOUS_ON_CONST; MIDPOINT_IN_SEGMENT] THEN
    REWRITE_TAC[midpoint] THEN CONJ_TAC THEN GEN_TAC THEN DISCH_TAC THEN
    UNDISCH_TAC `~(a:real^M = b)` THEN REWRITE_TAC[CONTRAPOS_THM] THEN
    VECTOR_ARITH_TAC;
    REPEAT STRIP_TAC THEN ASM_CASES_TAC `t:real^N->bool = u` THENL
     [EXISTS_TAC `(\x. b):real^N->real^M` THEN
      ASM_REWRITE_TAC[NOT_IN_EMPTY; ENDS_IN_SEGMENT; IN_UNIV;
                      CONTINUOUS_ON_CONST];
      SUBGOAL_THEN `?c:real^N. c IN u /\ ~(c IN t)` STRIP_ASSUME_TAC THENL
       [REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_SUBSET)) THEN
        REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN ASM SET_TAC[];
        ALL_TAC] THEN
      MP_TAC(ISPECL [`{c:real^N}`; `t:real^N->bool`; `u:real^N->bool`;
                     `midpoint(a,b):real^M`; `b:real^M`] lemma) THEN
      ASM_REWRITE_TAC[CLOSED_IN_SING; MIDPOINT_EQ_ENDPOINT] THEN
      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
      MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[NOT_IN_EMPTY] THEN
      X_GEN_TAC `f:real^N->real^M` THEN STRIP_TAC THEN CONJ_TAC THENL
       [SUBGOAL_THEN
         `segment[midpoint(a,b):real^M,b] SUBSET segment[a,b]` MP_TAC
        THENL
         [REWRITE_TAC[SUBSET; IN_SEGMENT; midpoint] THEN GEN_TAC THEN
          DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
          EXISTS_TAC `(&1 + u) / &2` THEN ASM_REWRITE_TAC[] THEN
          REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
          VECTOR_ARITH_TAC;
          ASM SET_TAC[]];
        SUBGOAL_THEN `~(a IN segment[midpoint(a,b):real^M,b])` MP_TAC THENL
         [ALL_TAC; ASM_MESON_TAC[]] THEN
        DISCH_THEN(MP_TAC o CONJUNCT2 o MATCH_MP DIST_IN_CLOSED_SEGMENT) THEN
        REWRITE_TAC[DIST_MIDPOINT] THEN
        UNDISCH_TAC `~(a:real^M = b)` THEN NORM_ARITH_TAC]]]);;  
 
let URYSOHN = prove
 (`!s t a b.
        closed s /\ closed t /\ s 
INTER t = {}
        ==> ?f:real^N->real^M.
               f 
continuous_on (:real^N) /\ (!x. f(x) 
IN segment[a,b]) /\
               (!x. x 
IN s ==> f x = a) /\ (!x. x 
IN t ==> f x = b)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Countability of some relevant sets.                                       *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Density of points with rational, or just dyadic rational, coordinates.    *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Various separability-type properties.                                     *)
(* ------------------------------------------------------------------------- *)
let SUBSET_SECOND_COUNTABLE = prove
 (`!s:real^N->bool.
       ?b. 
COUNTABLE b /\
           (!c. c 
IN b ==> ~(c = {}) /\ 
open_in(subtopology euclidean s) c) /\
           !t. 
open_in(subtopology euclidean s) t
               ==> ?u. u 
SUBSET b /\ t = 
UNIONS u`,
  GEN_TAC THEN
  SUBGOAL_THEN
   `?b. 
COUNTABLE b /\
           (!c:real^N->bool. c 
IN b ==> 
open_in(subtopology euclidean s) c) /\
           !t. 
open_in(subtopology euclidean s) t
               ==> ?u. u 
SUBSET b /\ t = 
UNIONS u`
  STRIP_ASSUME_TAC THENL
   [X_CHOOSE_THEN `B:(real^N->bool)->bool` STRIP_ASSUME_TAC
      
UNIV_SECOND_COUNTABLE THEN
    EXISTS_TAC `{s 
INTER c :real^N->bool | c 
IN B}` THEN
    ASM_SIMP_TAC[
SIMPLE_IMAGE; 
COUNTABLE_IMAGE] THEN
    ASM_SIMP_TAC[
FORALL_IN_IMAGE; 
EXISTS_SUBSET_IMAGE; 
OPEN_IN_OPEN_INTER] THEN
    REWRITE_TAC[
OPEN_IN_OPEN] THEN
    X_GEN_TAC `t:real^N->bool` THEN
    DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
    FIRST_X_ASSUM SUBST_ALL_TAC THEN
    SUBGOAL_THEN `?b. b 
SUBSET B /\ u:real^N->bool = 
UNIONS b`
    STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
    FIRST_X_ASSUM SUBST_ALL_TAC THEN
    EXISTS_TAC `b:(real^N->bool)->bool` THEN ASM_REWRITE_TAC[] THEN
    REWRITE_TAC[
INTER_UNIONS] THEN AP_TERM_TAC THEN SET_TAC[];
    EXISTS_TAC `b 
DELETE ({}:real^N->bool)` THEN
    ASM_SIMP_TAC[
COUNTABLE_DELETE; 
IN_DELETE; 
SUBSET_DELETE] THEN
    X_GEN_TAC `t:real^N->bool` THEN DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN
    DISCH_THEN(X_CHOOSE_THEN `u:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `u 
DELETE ({}:real^N->bool)` THEN
    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
    FIRST_X_ASSUM SUBST_ALL_TAC THEN
    REWRITE_TAC[
EXTENSION; 
IN_UNIONS] THEN
    GEN_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
    REWRITE_TAC[
IN_DELETE] THEN SET_TAC[]]);;
 
 
let OPEN_COUNTABLE_UNION_OPEN_INTERVALS,
    OPEN_COUNTABLE_UNION_CLOSED_INTERVALS = (CONJ_PAIR o prove)
 (`(!s:real^N->bool.
        open s
        ==> ?D. COUNTABLE D /\
                (!i. i IN D ==> i SUBSET s /\ ?a b. i = interval(a,b)) /\
                UNIONS D = s) /\
   (!s:real^N->bool.
        open s
        ==> ?D. COUNTABLE D /\
                (!i. i IN D ==> i SUBSET s /\ ?a b. i = interval[a,b]) /\
                UNIONS D = s)`,
  REPEAT STRIP_TAC THENL
   [EXISTS_TAC
     `{i | i IN IMAGE (\(a:real^N,b). interval(a,b))
            ({x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)} CROSS
             {x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)}) /\
           i SUBSET s}`;
    EXISTS_TAC
     `{i | i IN IMAGE (\(a:real^N,b). interval[a,b])
            ({x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)} CROSS
             {x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)}) /\
           i SUBSET s}`] THEN
  (SIMP_TAC[COUNTABLE_RESTRICT; COUNTABLE_IMAGE; COUNTABLE_CROSS;
           COUNTABLE_RATIONAL_COORDINATES] THEN
   REWRITE_TAC[IN_ELIM_THM; UNIONS_GSPEC; IMP_CONJ; GSYM CONJ_ASSOC] THEN
   REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
   REWRITE_TAC[FORALL_PAIR_THM; EXISTS_PAIR_THM; IN_CROSS; IN_ELIM_THM] THEN
   CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
   REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
   X_GEN_TAC `x:real^N` THEN EQ_TAC THENL [SET_TAC[]; DISCH_TAC] THEN
   FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N` o REWRITE_RULE[open_def]) THEN
   ASM_REWRITE_TAC[] THEN
   DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
   SUBGOAL_THEN
    `!i. 1 <= i /\ i <= dimindex(:N)
         ==> ?a b. rational a /\ rational b /\
                   a < (x:real^N)$i /\ (x:real^N)$i < b /\
                   abs(b - a) < e / &(dimindex(:N))`
   MP_TAC THENL
    [REPEAT STRIP_TAC THEN MATCH_MP_TAC RATIONAL_APPROXIMATION_STRADDLE THEN
     ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1];
     REWRITE_TAC[LAMBDA_SKOLEM]] THEN
   MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
   MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:real^N` THEN
   DISCH_TAC THEN ASM_SIMP_TAC[SUBSET; IN_INTERVAL; REAL_LT_IMP_LE] THEN
   X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
   REWRITE_TAC[dist] THEN MP_TAC(ISPEC `y - x:real^N` NORM_LE_L1) THEN
   MATCH_MP_TAC(REAL_ARITH `s < e ==> n <= s ==> n < e`) THEN
   MATCH_MP_TAC SUM_BOUND_LT_GEN THEN
   REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; NOT_LT; CARD_NUMSEG_1] THEN
   REWRITE_TAC[DIMINDEX_GE_1; IN_NUMSEG; VECTOR_SUB_COMPONENT] THEN
   X_GEN_TAC `k:num` THEN STRIP_TAC THEN
   REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `k:num`)) THEN ASM_REWRITE_TAC[] THEN
   ASM_REAL_ARITH_TAC));;
let LIMPT_OF_CONDENSATION_POINTS,CONDENSATION_POINT_OF_CONDENSATION_POINTS =
  (CONJ_PAIR o prove)
 (`(!x:real^N s.
        x limit_point_of {y | y condensation_point_of s} <=>
        x condensation_point_of s) /\
   (!x:real^N s.
        x condensation_point_of {y | y condensation_point_of s} <=>
        x condensation_point_of s)`,
  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT
   `(r ==> q) /\ (q ==> p) /\ (p ==> r)
    ==> (q <=> p) /\ (r <=> p)`) THEN
  REWRITE_TAC[CONDENSATION_POINT_IMP_LIMPT] THEN CONJ_TAC THENL
   [REWRITE_TAC[LIMPT_APPROACHABLE; CONDENSATION_POINT_INFINITE_BALL] THEN
    REPEAT GEN_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
    DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
    ASM_REWRITE_TAC[REAL_HALF; CONTRAPOS_THM] THEN
    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] COUNTABLE_SUBSET) THEN
    SIMP_TAC[SUBSET; IN_INTER; IN_BALL] THEN
    REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC;
    ONCE_REWRITE_TAC[CONDENSATION_POINT_INFINITE_BALL] THEN DISCH_TAC THEN
    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
    ASM_REWRITE_TAC[REAL_HALF] THEN DISCH_THEN(MP_TAC o MATCH_MP
     (MESON[CARD_EQ_CONDENSATION_POINTS_IN_SET; CARD_COUNTABLE_CONG]
        `~COUNTABLE s
         ==> ~COUNTABLE {x | x IN s /\ x condensation_point_of s}`)) THEN
    REWRITE_TAC[UNCOUNTABLE_REAL; CONTRAPOS_THM] THEN
    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] COUNTABLE_SUBSET) THEN
    REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTER] THEN X_GEN_TAC `y:real^N` THEN
    REPEAT STRIP_TAC THENL
     [ASM_MESON_TAC[CONDENSATION_POINT_OF_SUBSET; INTER_SUBSET]; ALL_TAC] THEN
    MATCH_MP_TAC(SET_RULE `!s. x IN s /\ s SUBSET t ==> x IN t`) THEN
    EXISTS_TAC `closure(s INTER ball(x:real^N,e / &2))` THEN CONJ_TAC THENL
     [REWRITE_TAC[closure; IN_UNION; IN_ELIM_THM] THEN DISJ2_TAC THEN
      ASM_SIMP_TAC[CONDENSATION_POINT_IMP_LIMPT];
      TRANS_TAC SUBSET_TRANS `closure(ball(x:real^N,e / &2))` THEN
      SIMP_TAC[SUBSET_CLOSURE; INTER_SUBSET] THEN
      ASM_SIMP_TAC[CLOSURE_BALL; REAL_HALF; SUBSET_BALLS; DIST_REFL] THEN
      ASM_REAL_ARITH_TAC]]);;
(* ------------------------------------------------------------------------- *)
(* A discrete set is countable, and an uncountable set has a limit point.    *)
(* ------------------------------------------------------------------------- *)
let DISCRETE_IMP_COUNTABLE = prove
 (`!s:real^N->bool.
        (!x. x 
IN s ==> ?e. &0 < e /\
                            !y. y 
IN s /\ ~(y = x) ==> e <= norm(y - x))
        ==> 
COUNTABLE s`,
  REPEAT STRIP_TAC THEN
  SUBGOAL_THEN
   `!x. x 
IN s
        ==> ?q. (!i. 1 <= i /\ i <= dimindex(:N) ==> rational(q$i)) /\
                !y:real^N. y 
IN s /\ ~(y = x) ==> norm(x - q) < norm(y - q)`
  MP_TAC THENL
   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
    MP_TAC(SET_RULE `x 
IN (:real^N)`) THEN
    REWRITE_TAC[GSYM 
CLOSURE_RATIONAL_COORDINATES] THEN
    REWRITE_TAC[
CLOSURE_APPROACHABLE; 
IN_ELIM_THM] THEN
    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[
REAL_HALF] THEN
    MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `q:real^N` THEN
    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
    X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`) THEN ASM_REWRITE_TAC[] THEN
    REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC;
    POP_ASSUM(K ALL_TAC) THEN
    REWRITE_TAC[
RIGHT_IMP_EXISTS_THM; 
SKOLEM_THM; 
LEFT_IMP_EXISTS_THM] THEN
    X_GEN_TAC `q:real^N->real^N` THEN DISCH_TAC THEN
    MP_TAC(ISPECL
     [`s:real^N->bool`;
      `{ x:real^N | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i) }`;
      `(:num)`] 
CARD_LE_TRANS) THEN
    REWRITE_TAC[
COUNTABLE; 
ge_c] THEN DISCH_THEN MATCH_MP_TAC THEN
    SIMP_TAC[REWRITE_RULE[
COUNTABLE; 
ge_c] 
COUNTABLE_RATIONAL_COORDINATES] THEN
    REWRITE_TAC[
le_c] THEN EXISTS_TAC `q:real^N->real^N` THEN
    ASM_SIMP_TAC[
IN_ELIM_THM] THEN ASM_MESON_TAC[
REAL_LT_ANTISYM]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* The Brouwer reduction theorem.                                            *)
(* ------------------------------------------------------------------------- *)
let BROUWER_REDUCTION_THEOREM_GEN = prove
 (`!P s:real^N->bool.
        (!f. (!n. closed(f n) /\ P(f n)) /\ (!n. f(SUC n) 
SUBSET f(n))
              ==> P(
INTERS {f n | n 
IN (:num)})) /\
        closed s /\ P s
        ==> ?t. t 
SUBSET s /\ closed t /\ P t /\
                (!u. u 
SUBSET s /\ closed u /\ P u ==> ~(u 
PSUBSET t))`,
  REPEAT STRIP_TAC THEN
  SUBGOAL_THEN
   `?b:num->real^N->bool.
        (!m n. b m = b n <=> m = n) /\
        (!n. open (b n)) /\
        (!s. open s ==> (?k. s = 
UNIONS {b n | n 
IN k}))`
  STRIP_ASSUME_TAC THENL
   [REWRITE_TAC[
UNIV_SECOND_COUNTABLE_SEQUENCE]; ALL_TAC] THEN
  X_CHOOSE_THEN `a:num->real^N->bool` MP_TAC
   (prove_recursive_functions_exist num_RECURSION
   `a 0 = (s:real^N->bool) /\
    (!n. a(SUC n) =
         if ?u. u 
SUBSET a(n) /\ closed u /\ P u /\ u 
INTER (b n) = {}
         then @u. u 
SUBSET a(n) /\ closed u /\ P u /\ u 
INTER (b n) = {}
         else a(n))`) THEN
  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "base") (LABEL_TAC "step")) THEN
  EXISTS_TAC `
INTERS {a n :real^N->bool | n 
IN (:num)}` THEN
  SUBGOAL_THEN `!n. (a:num->real^N->bool)(SUC n) 
SUBSET a(n)` ASSUME_TAC THENL
   [GEN_TAC THEN ASM_REWRITE_TAC[] THEN
    COND_CASES_TAC THEN REWRITE_TAC[
SUBSET_REFL] THEN
    FIRST_X_ASSUM(MP_TAC o SELECT_RULE) THEN MESON_TAC[];
    ALL_TAC] THEN
  SUBGOAL_THEN `!n. (a:num->real^N->bool) n 
SUBSET s` ASSUME_TAC THENL
   [INDUCT_TAC THEN ASM_MESON_TAC[
SUBSET_REFL; 
SUBSET_TRANS]; ALL_TAC] THEN
  SUBGOAL_THEN `!n. closed((a:num->real^N->bool) n) /\ P(a n)` ASSUME_TAC THENL
   [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN
    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
    FIRST_X_ASSUM(MP_TAC o SELECT_RULE) THEN MESON_TAC[];
    ALL_TAC] THEN
  REPEAT CONJ_TAC THENL
   [ASM SET_TAC[];
    MATCH_MP_TAC 
CLOSED_INTERS THEN
    ASM_REWRITE_TAC[
FORALL_IN_GSPEC; 
IN_UNIV] THEN SET_TAC[];
    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[];
    X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
    REWRITE_TAC[
PSUBSET_ALT] THEN
    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
    REWRITE_TAC[
INTERS_GSPEC; 
EXISTS_IN_GSPEC; 
IN_UNIV] THEN
    DISCH_THEN(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
    SUBGOAL_THEN
     `?n. x 
IN (b:num->real^N->bool)(n) /\ t 
INTER b n = {}`
    STRIP_ASSUME_TAC THENL
     [MP_TAC(ISPEC `(:real^N) 
DIFF t` 
OPEN_CONTAINS_BALL) THEN
      ASM_REWRITE_TAC[GSYM closed] THEN
      DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
      ASM_REWRITE_TAC[
IN_DIFF; 
IN_UNIV; 
LEFT_IMP_EXISTS_THM] THEN
      REWRITE_TAC[SET_RULE `s 
SUBSET UNIV DIFF t <=> t 
INTER s = {}`] THEN
      X_GEN_TAC `e:real` THEN
      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
      MP_TAC(ISPECL [`x:real^N`; `e:real`] 
CENTRE_IN_BALL) THEN
      FIRST_X_ASSUM(MP_TAC o SPEC `ball(x:real^N,e)`) THEN
      ASM_REWRITE_TAC[
OPEN_BALL; 
LEFT_IMP_EXISTS_THM] THEN
      X_GEN_TAC `k:num->bool` THEN DISCH_THEN SUBST1_TAC THEN
      REWRITE_TAC[
IN_UNIONS; 
INTER_UNIONS; 
EMPTY_UNIONS; 
FORALL_IN_GSPEC] THEN
      SET_TAC[];
      REMOVE_THEN "step" (MP_TAC o SPEC `n:num`) THEN
      COND_CASES_TAC THENL
       [DISCH_THEN(ASSUME_TAC o SYM) THEN
        FIRST_X_ASSUM(MP_TAC o SELECT_RULE) THEN ASM_REWRITE_TAC[] THEN
        ASM SET_TAC[];
        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
NOT_EXISTS_THM]) THEN
        DISCH_THEN(MP_TAC o SPEC `t:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
        ASM SET_TAC[]]]]);;
 
 
let BROUWER_REDUCTION_THEOREM = prove
 (`!P s:real^N->bool.
        (!f. (!n. compact(f n) /\ ~(f n = {}) /\ P(f n)) /\
             (!n. f(SUC n) 
SUBSET f(n))
             ==> P(
INTERS {f n | n 
IN (:num)})) /\
        compact s /\ ~(s = {}) /\ P s
        ==> ?t. t 
SUBSET s /\ compact t /\ ~(t = {}) /\ P t /\
                (!u. u 
SUBSET s /\ closed u /\ ~(u = {}) /\ P u
                     ==> ~(u 
PSUBSET t))`,
 
 
(* ------------------------------------------------------------------------- *)
(* The Arzela-Ascoli theorem.                                                *)
(* ------------------------------------------------------------------------- *)
let SUBSEQUENCE_DIAGONALIZATION_LEMMA = prove
 (`!P:num->(num->A)->bool.
    (!i r:num->A. ?k. (!m n. m < n ==> k m < k n) /\ P i (r o k)) /\
    (!i r:num->A k1 k2 N.
        P i (r o k1) /\ (!j. N <= j ==> ?j'. j <= j' /\ k2 j = k1 j')
        ==> P i (r o k2))
    ==> !r:num->A. ?k. (!m n. m < n ==> k m < k n) /\ (!i. P i (r o k))`,
  REPEAT GEN_TAC THEN
  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [
SKOLEM_THM] THEN
  REWRITE_TAC[
FORALL_AND_THM; TAUT
   `(p ==> q /\ r) <=> (p ==> q) /\ (p ==> r)`] THEN
  DISCH_THEN(X_CHOOSE_THEN
   `kk:num->(num->A)->num->num` STRIP_ASSUME_TAC) THEN
  X_GEN_TAC `r:num->A` THEN
  (STRIP_ASSUME_TAC o prove_recursive_functions_exist num_RECURSION)
    `(rr 0 = (kk:num->(num->A)->num->num) 0 r) /\
     (!n. rr(SUC n) = rr n o kk (SUC n) (r o rr n))` THEN
  EXISTS_TAC `\n. (rr:num->num->num) n n` THEN REWRITE_TAC[ETA_AX] THEN
  SUBGOAL_THEN
   `(!i. (!m n. m < n ==> (rr:num->num->num) i m < rr i n)) /\
    (!i. (P:num->(num->A)->bool) i (r o rr i))`
  STRIP_ASSUME_TAC THENL
   [REWRITE_TAC[
AND_FORALL_THM] THEN
    INDUCT_TAC THEN ASM_REWRITE_TAC[
o_ASSOC] THEN
    REWRITE_TAC[
o_THM] THEN ASM_MESON_TAC[];
    ALL_TAC] THEN
  SUBGOAL_THEN `!i j n. i <= j ==> (rr:num->num->num) i n <= rr j n`
  ASSUME_TAC THENL
   [REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [
LE_EXISTS] THEN
    SIMP_TAC[
LEFT_IMP_EXISTS_THM] THEN SPEC_TAC(`j:num`,`j:num`) THEN
    ONCE_REWRITE_TAC[
SWAP_FORALL_THM] THEN SIMP_TAC[
FORALL_UNWIND_THM2] THEN
    INDUCT_TAC THEN REWRITE_TAC[
ADD_CLAUSES; 
LE_REFL] THEN
    ASM_REWRITE_TAC[] THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
     (REWRITE_RULE[
IMP_CONJ] 
LE_TRANS)) THEN REWRITE_TAC[
o_THM] THEN
    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
     (MESON[
LE_LT]
       `!f:num->num.
        (!m n. m < n ==> f m < f n) ==> (!m n. m <= n ==> f m <= f n)`) o
       SPEC `i + d:num`) THEN
    SPEC_TAC(`n:num`,`n:num`) THEN MATCH_MP_TAC 
MONOTONE_BIGGER THEN
    ASM_SIMP_TAC[];
    ALL_TAC] THEN
  CONJ_TAC THENL
   [MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN DISCH_TAC THEN
    MATCH_MP_TAC 
LET_TRANS THEN
    EXISTS_TAC `(rr:num->num->num) n m` THEN
    ASM_MESON_TAC[
LT_IMP_LE];
    ALL_TAC] THEN
  SUBGOAL_THEN
   `!m n i. n <= m ==> ?j. i <= j /\ (rr:num->num->num) m i = rr n j`
  ASSUME_TAC THENL
   [ALL_TAC;
    X_GEN_TAC `i:num` THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
    EXISTS_TAC `(rr:num->num->num) i` THEN ASM_REWRITE_TAC[] THEN
    EXISTS_TAC `i:num` THEN ASM_MESON_TAC[]] THEN
  SUBGOAL_THEN
   `!p d i. ?j. i <= j /\ (rr:num->num->num) (p + d) i = rr p j`
   (fun th -> MESON_TAC[
LE_EXISTS; th]) THEN
  X_GEN_TAC `p:num` THEN  MATCH_MP_TAC 
num_INDUCTION THEN
  ASM_REWRITE_TAC[
ADD_CLAUSES] THEN CONJ_TAC THENL
   [MESON_TAC[
LE_REFL]; ALL_TAC] THEN
  X_GEN_TAC `d:num` THEN DISCH_THEN(LABEL_TAC "+") THEN
  X_GEN_TAC `i:num` THEN ASM_REWRITE_TAC[
o_THM] THEN
  REMOVE_THEN "+" (MP_TAC o SPEC
   `(kk:num->(num->A)->num->num) (SUC(p + d))
        ((r:num->A) o (rr:num->num->num) (p + d)) i`) THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `j:num` THEN
  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
  MATCH_MP_TAC(REWRITE_RULE[
IMP_CONJ] 
LE_TRANS) THEN
  SPEC_TAC(`i:num`,`i:num`) THEN MATCH_MP_TAC 
MONOTONE_BIGGER THEN
  ASM_REWRITE_TAC[
o_THM] THEN ASM_MESON_TAC[]);;
 
 
let FUNCTION_CONVERGENT_SUBSEQUENCE = prove
 (`!f:num->real^M->real^N s M.
        
COUNTABLE s /\ (!n x. x 
IN s ==> norm(f n x) <= M)
        ==> ?k. (!m n:num. m < n ==> k m < k n) /\
                !x. x 
IN s ==> ?l. ((\n. f (k n) x) --> l) sequentially`,
  REPEAT STRIP_TAC THEN
  ASM_CASES_TAC `s:real^M->bool = {}` THENL
   [EXISTS_TAC `\n:num. n` THEN ASM_REWRITE_TAC[
NOT_IN_EMPTY];
    ALL_TAC] THEN
  MP_TAC(ISPEC `s:real^M->bool` 
COUNTABLE_AS_IMAGE) THEN
  ASM_REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
  X_GEN_TAC `X:num->real^M` THEN DISCH_THEN SUBST_ALL_TAC THEN
  MP_TAC(ISPEC
    `\i r. ?l. ((\n. ((f:num->real^M->real^N) o (r:num->num)) n
                     ((X:num->real^M) i)) --> l) sequentially`
   
SUBSEQUENCE_DIAGONALIZATION_LEMMA) THEN
  REWRITE_TAC[
FORALL_IN_IMAGE; 
o_THM; 
IN_UNIV] THEN
  ANTS_TAC THENL [ALL_TAC; DISCH_THEN MATCH_ACCEPT_TAC] THEN CONJ_TAC THENL
   [RULE_ASSUM_TAC(REWRITE_RULE[
FORALL_IN_IMAGE; 
IN_UNIV]) THEN
    MAP_EVERY X_GEN_TAC [`i:num`; `r:num->num`] THEN
    MP_TAC(ISPEC `cball(vec 0:real^N,M)` compact) THEN
    REWRITE_TAC[
COMPACT_CBALL] THEN DISCH_THEN(MP_TAC o SPEC
     `\n. (f:num->real^M->real^N) ((r:num->num) n) (X(i:num))`) THEN
    ASM_REWRITE_TAC[
IN_CBALL_0; 
o_DEF] THEN MESON_TAC[];
    REPEAT GEN_TAC THEN REWRITE_TAC[
LIM_SEQUENTIALLY; 
GE] THEN
    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
    MATCH_MP_TAC 
MONO_EXISTS THEN GEN_TAC THEN
    MATCH_MP_TAC 
MONO_FORALL THEN GEN_TAC THEN
    MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
    ASM_MESON_TAC[
LE_TRANS; ARITH_RULE `
MAX a b <= c <=> a <= c /\ b <= c`]]);;
 
 
let ARZELA_ASCOLI = prove
 (`!f:num->real^M->real^N s M.
        compact s /\
        (!n x. x 
IN s ==> norm(f n x) <= M) /\
        (!x e. x 
IN s /\ &0 < e
               ==> ?d. &0 < d /\
                       !n y. y 
IN s /\ norm(x - y) < d
                             ==> norm(f n x - f n y) < e)
        ==> ?g. g 
continuous_on s /\
                ?r. (!m n:num. m < n ==> r m < r n) /\
                    !e. &0 < e
                        ==> ?N. !n x. n >= N /\ x 
IN s
                                      ==> norm(f(r n) x - g x) < e`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[
GE] THEN
  MATCH_MP_TAC(MESON[]
   `(!k g. V k g ==> N g) /\ (?k. M k /\ ?g. V k g)
    ==> ?g. N g /\ ?k. M k /\ V k g`) THEN
  CONJ_TAC THENL
   [MAP_EVERY X_GEN_TAC [`k:num->num`; `g:real^M->real^N`] THEN
    STRIP_TAC THEN MATCH_MP_TAC(ISPEC `sequentially`
      
CONTINUOUS_UNIFORM_LIMIT) THEN
    EXISTS_TAC `(f:num->real^M->real^N) o (k:num->num)` THEN
    ASM_SIMP_TAC[
EVENTUALLY_SEQUENTIALLY; 
o_THM; 
TRIVIAL_LIMIT_SEQUENTIALLY;
                 
RIGHT_IMP_FORALL_THM; IMP_IMP] THEN
    EXISTS_TAC `0` THEN REWRITE_TAC[
continuous_on; dist] THEN
    ASM_MESON_TAC[
NORM_SUB];
    ALL_TAC] THEN
  MP_TAC(ISPECL
   [`
IMAGE (f:num->real^M->real^N) (:num)`;
    `s:real^M->bool`]
   
COMPACT_UNIFORMLY_EQUICONTINUOUS) THEN
  REWRITE_TAC[
IMP_CONJ; 
RIGHT_FORALL_IMP_THM; 
FORALL_IN_IMAGE; 
IN_UNIV] THEN
  ANTS_TAC THENL
   [REWRITE_TAC[dist] THEN ONCE_REWRITE_TAC[
NORM_SUB] THEN ASM_MESON_TAC[];
    ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(K ALL_TAC o SPEC `x:real^M`)] THEN
  REWRITE_TAC[
RIGHT_IMP_FORALL_THM] THEN
  REWRITE_TAC[IMP_IMP; GSYM 
CONJ_ASSOC; dist] THEN
  DISCH_THEN(ASSUME_TAC o ONCE_REWRITE_RULE[
NORM_SUB]) THEN
  REWRITE_TAC[GSYM dist; 
UNIFORMLY_CONVERGENT_EQ_CAUCHY] THEN
  X_CHOOSE_THEN `r:real^M->bool` STRIP_ASSUME_TAC
   (ISPEC `s:real^M->bool` 
SEPARABLE) THEN
  MP_TAC(ISPECL [`f:num->real^M->real^N`; `r:real^M->bool`; `M:real`]
        
FUNCTION_CONVERGENT_SUBSEQUENCE) THEN
  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `k:num->num` THEN
  REWRITE_TAC[
CONVERGENT_EQ_CAUCHY; cauchy] THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*")) THEN
  ASM_REWRITE_TAC[] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &3`) THEN
  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
COMPACT_EQ_HEINE_BOREL]) THEN
  DISCH_THEN(MP_TAC o SPEC `
IMAGE (\x:real^M. ball(x,d)) r`) THEN
  REWRITE_TAC[
FORALL_IN_IMAGE; 
OPEN_BALL] THEN
  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN
  REWRITE_TAC[
EXISTS_FINITE_SUBSET_IMAGE] THEN ANTS_TAC THENL
   [MATCH_MP_TAC 
SUBSET_TRANS THEN EXISTS_TAC `closure r:real^M->bool` THEN
    ASM_REWRITE_TAC[] THEN REWRITE_TAC[
SUBSET; 
CLOSURE_APPROACHABLE] THEN
    X_GEN_TAC `x:real^M` THEN DISCH_THEN(MP_TAC o SPEC `d:real`) THEN
    ASM_REWRITE_TAC[
UNIONS_IMAGE; 
IN_ELIM_THM; 
IN_BALL];
    DISCH_THEN(X_CHOOSE_THEN `t:real^M->bool` STRIP_ASSUME_TAC)] THEN
  REMOVE_THEN "*" MP_TAC THEN REWRITE_TAC[
RIGHT_IMP_FORALL_THM] THEN
  GEN_REWRITE_TAC LAND_CONV [
SWAP_FORALL_THM] THEN
  DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
  ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &3 <=> &0 < e`] THEN
  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [
RIGHT_IMP_EXISTS_THM] THEN
  REWRITE_TAC[
SKOLEM_THM; 
LEFT_IMP_EXISTS_THM] THEN
  X_GEN_TAC `M:real^M->num` THEN DISCH_THEN(LABEL_TAC "*") THEN
  MP_TAC(ISPECL [`M:real^M->num`; `t:real^M->bool`]
    
UPPER_BOUND_FINITE_SET) THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
  DISCH_TAC THEN
  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`; `x:real^M`] THEN STRIP_TAC THEN
  UNDISCH_TAC `s 
SUBSET UNIONS (
IMAGE (\x:real^M. ball (x,d)) t)` THEN
  REWRITE_TAC[
SUBSET; 
UNIONS_IMAGE; 
IN_ELIM_THM] THEN
  DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN
  ASM_REWRITE_TAC[
IN_BALL; 
LEFT_IMP_EXISTS_THM; dist] THEN
  X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
  MATCH_MP_TAC(NORM_ARITH
   `norm(f (k(m:num)) y - f (k m) x) < e / &3 /\
    norm(f (k n) y - f (k n) x) < e / &3 /\
    norm(f (k m) y - f (k n) y) < e / &3
    ==> norm(f (k m) x - f (k n) x :real^M) < e`) THEN
  ASM_SIMP_TAC[] THEN REMOVE_THEN "*" (MP_TAC o SPEC `y:real^M`) THEN
  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
  DISCH_THEN(MP_TAC o SPECL [`m:num`; `n:num`]) THEN
  ASM_REWRITE_TAC[dist; 
GE] THEN ASM_MESON_TAC[
SUBSET; 
LE_TRANS]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Two forms of the Baire propery of dense sets.                             *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Several variants of paracompactness.                                      *)
(* ------------------------------------------------------------------------- *)
let PARACOMPACT = prove
 (`!s c. (!t:real^N->bool. t 
IN c ==> open t) /\ s 
SUBSET UNIONS c
         ==> ?c'. s 
SUBSET UNIONS c' /\
                  (!u. u 
IN c'
                       ==> open u /\ ?t. t 
IN c /\ u 
SUBSET t) /\
                  (!x. x 
IN s
                       ==> ?v. open v /\ x 
IN v /\
                               
FINITE {u | u 
IN c' /\ ~(u 
INTER v = {})})`,
  REPEAT STRIP_TAC THEN
  ASM_CASES_TAC `s:real^N->bool = {}` THENL
   [EXISTS_TAC `{}:(real^N->bool)->bool` THEN
    ASM_REWRITE_TAC[
EMPTY_SUBSET; 
NOT_IN_EMPTY];
    ALL_TAC] THEN
  SUBGOAL_THEN
   `!x:real^N. x 
IN s
               ==> ?t u. x 
IN u /\ open u /\ closure u 
SUBSET t /\ t 
IN c`
  MP_TAC THENL
   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N` o GEN_REWRITE_RULE I [
SUBSET]) THEN
    ASM_REWRITE_TAC[
IN_UNIONS] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
    X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `t:real^N->bool`) THEN
    ASM_REWRITE_TAC[] THEN
    GEN_REWRITE_TAC LAND_CONV [
OPEN_CONTAINS_CBALL] THEN
    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `ball(x:real^N,e)` THEN
    ASM_SIMP_TAC[
OPEN_BALL; 
CENTRE_IN_BALL; 
CLOSURE_BALL];
    GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [
RIGHT_IMP_EXISTS_THM] THEN
    REWRITE_TAC[
LEFT_IMP_EXISTS_THM; 
SKOLEM_THM] THEN
    MAP_EVERY X_GEN_TAC
      [`f:real^N->real^N->bool`; `e:real^N->real^N->bool`] THEN
    STRIP_TAC] THEN
  MP_TAC(ISPEC `
IMAGE (e:real^N->real^N->bool) s` 
LINDELOF) THEN
  ASM_SIMP_TAC[
FORALL_IN_IMAGE] THEN
  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
  REWRITE_TAC[
EXISTS_COUNTABLE_SUBSET_IMAGE] THEN
  DISCH_THEN(X_CHOOSE_THEN `k:real^N->bool`
    (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  ASM_CASES_TAC `k:real^N->bool = {}` THENL
   [ASM_REWRITE_TAC[] THEN ASM SET_TAC[]; ALL_TAC] THEN
  MP_TAC(ISPEC `k:real^N->bool` 
COUNTABLE_AS_IMAGE) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `a:num->real^N` SUBST_ALL_TAC) THEN
  STRIP_TAC THEN EXISTS_TAC
  `{ f(a n:real^N) 
DIFF UNIONS {closure(e(a m)):real^N->bool | m < n} |
     n 
IN (:num)}` THEN
  REWRITE_TAC[
FORALL_IN_GSPEC; 
IN_UNIV] THEN REPEAT CONJ_TAC THENL
   [X_GEN_TAC `n:num` THEN CONJ_TAC THENL
     [MATCH_MP_TAC 
OPEN_DIFF THEN
      CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
      MATCH_MP_TAC 
CLOSED_UNIONS THEN
      REWRITE_TAC[
FORALL_IN_GSPEC; 
CLOSED_CLOSURE] THEN
      ONCE_REWRITE_TAC[
SIMPLE_IMAGE_GEN] THEN
      SIMP_TAC[
FINITE_IMAGE; 
FINITE_NUMSEG_LT];
      EXISTS_TAC `f((a:num->real^N) n):real^N->bool` THEN ASM SET_TAC[]];
    REWRITE_TAC[
SUBSET; 
UNIONS_GSPEC; 
IN_ELIM_THM; 
IN_DIFF] THEN
    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
    SUBGOAL_THEN `?n. x 
IN (f((a:num->real^N) n):real^N->bool)` MP_TAC THENL
     [RULE_ASSUM_TAC(REWRITE_RULE[
UNIONS_IMAGE; 
EXISTS_IN_IMAGE]) THEN
      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
EXTENSION]) THEN
      DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
      ASM_REWRITE_TAC[
IN_ELIM_THM; 
IN_UNIV] THEN
      DISCH_THEN(MP_TAC o snd o EQ_IMP_RULE) THEN
      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
      MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `n:num` THEN
      STRIP_TAC THEN
      FIRST_X_ASSUM(MP_TAC o SPEC `(a:num->real^N) n`) THEN
      ANTS_TAC THENL [ASM SET_TAC[]; ASM_MESON_TAC[
CLOSURE_SUBSET; 
SUBSET]];
      GEN_REWRITE_TAC LAND_CONV [
num_WOP] THEN
      MATCH_MP_TAC 
MONO_EXISTS THEN ASM SET_TAC[]];
    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
    RULE_ASSUM_TAC(REWRITE_RULE[
UNIONS_IMAGE; 
EXISTS_IN_IMAGE]) THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
EXTENSION]) THEN
    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
    ASM_REWRITE_TAC[
IN_ELIM_THM; 
IN_UNIV] THEN
    DISCH_THEN(MP_TAC o snd o EQ_IMP_RULE) THEN
    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
    DISCH_THEN(X_CHOOSE_TAC `n:num`) THEN
    EXISTS_TAC `e((a:num->real^N) n):real^N->bool` THEN
    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
    REWRITE_TAC[SET_RULE
     `{u | (?n. u = f n) /\ P u} = 
IMAGE f {n |n| P(f n) /\ n 
IN (:num)}`] THEN
    MATCH_MP_TAC 
FINITE_IMAGE THEN MATCH_MP_TAC 
FINITE_SUBSET THEN
    EXISTS_TAC `{m:num | m <= n}` THEN REWRITE_TAC[
FINITE_NUMSEG_LE] THEN
    REWRITE_TAC[
SUBSET; 
IN_ELIM_THM; 
IN_UNIV] THEN
    X_GEN_TAC `m:num` THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
    REWRITE_TAC[
NOT_LE] THEN DISCH_TAC THEN
    MATCH_MP_TAC(SET_RULE `u 
SUBSET t ==> (s 
DIFF t) 
INTER u = {}`) THEN
    REWRITE_TAC[
SUBSET; 
IN_UNIONS; 
EXISTS_IN_GSPEC] THEN
    ASM_MESON_TAC[
CLOSURE_SUBSET; 
SUBSET]]);;
 
 
let PARACOMPACT_CLOSED_IN = prove
 (`!u:real^N->bool s c.
        
closed_in (subtopology euclidean u) s /\
        (!t:real^N->bool. t 
IN c ==> 
open_in (subtopology euclidean u) t) /\
        s 
SUBSET UNIONS c
         ==> ?c'. s 
SUBSET UNIONS c' /\
                  (!v. v 
IN c'
                       ==> 
open_in (subtopology euclidean u) v /\
                           ?t. t 
IN c /\ v 
SUBSET t) /\
                  (!x. x 
IN u
                       ==> ?v. 
open_in (subtopology euclidean u) v /\ x 
IN v /\
                               
FINITE {n | n 
IN c' /\ ~(n 
INTER v = {})})`,
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
   (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
  REWRITE_TAC[
OPEN_IN_OPEN] THEN
  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [
RIGHT_IMP_EXISTS_THM] THEN
  REWRITE_TAC[
SKOLEM_THM; 
LEFT_IMP_EXISTS_THM] THEN
  X_GEN_TAC `uu:(real^N->bool)->(real^N->bool)` THEN
  DISCH_THEN(ASSUME_TAC o GSYM) THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
CLOSED_IN_CLOSED]) THEN
  DISCH_THEN(X_CHOOSE_THEN `k:real^N->bool`
   (CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC)) THEN
  MP_TAC(ISPECL
   [`u:real^N->bool`;
    `((:real^N) 
DIFF k) 
INSERT IMAGE (uu:(real^N->bool)->(real^N->bool)) c`]
   
PARACOMPACT) THEN
  ASM_SIMP_TAC[
FORALL_IN_IMAGE; 
UNIONS_IMAGE; 
UNIONS_INSERT; 
FORALL_IN_INSERT;
               
EXISTS_IN_IMAGE; 
EXISTS_IN_INSERT; GSYM closed] THEN
  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `{u 
INTER v:real^N->bool | v 
IN d /\ ~(v 
INTER k = {})}` THEN
  REPEAT CONJ_TAC THENL
   [REWRITE_TAC[
UNIONS_GSPEC] THEN ASM SET_TAC[];
    REWRITE_TAC[
FORALL_IN_GSPEC] THEN ASM SET_TAC[];
    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
    DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `u 
INTER v:real^N->bool` THEN ASM_REWRITE_TAC[
IN_INTER] THEN
    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
    ONCE_REWRITE_TAC[SET_RULE
     `{y | y 
IN {f x | P x} /\ Q y} = 
IMAGE f {x | P x /\ Q(f x)}`] THEN
    MATCH_MP_TAC 
FINITE_IMAGE THEN
    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
     (REWRITE_RULE[
IMP_CONJ] 
FINITE_SUBSET)) THEN SET_TAC[]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Partitions of unity subordinate to locally finite open coverings.         *)
(* ------------------------------------------------------------------------- *)