(*              (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.                                        *)
(* ------------------------------------------------------------------------- *)

let sphere = new_definition
  `sphere(x,e) = { y | dist(x,y) = e}`;;
let IN_SPHERE = 
prove (`!x y e. y IN sphere(x,e) <=> dist(x,y) = e`,
REWRITE_TAC[sphere; IN_ELIM_THM]);;
let IN_BALL_0 = 
prove (`!x e. x IN ball(vec 0,e) <=> norm(x) < e`,
REWRITE_TAC[IN_BALL; dist; VECTOR_SUB_LZERO; NORM_NEG]);;
let IN_CBALL_0 = 
prove (`!x e. x IN cball(vec 0,e) <=> norm(x) <= e`,
REWRITE_TAC[IN_CBALL; dist; VECTOR_SUB_LZERO; NORM_NEG]);;
let IN_SPHERE_0 = 
prove (`!x e. x IN sphere(vec 0,e) <=> norm(x) = e`,
REWRITE_TAC[IN_SPHERE; dist; VECTOR_SUB_LZERO; NORM_NEG]);;
let BALL_TRIVIAL = 
prove (`!x. ball(x,&0) = {}`,
REWRITE_TAC[EXTENSION; IN_BALL; IN_SING; NOT_IN_EMPTY] THEN NORM_ARITH_TAC);;
let CBALL_TRIVIAL = 
prove (`!x. cball(x,&0) = {x}`,
REWRITE_TAC[EXTENSION; IN_CBALL; IN_SING; NOT_IN_EMPTY] THEN NORM_ARITH_TAC);;
let CENTRE_IN_CBALL = 
prove (`!x e. x IN cball(x,e) <=> &0 <= e`,
MESON_TAC[IN_CBALL; DIST_REFL]);;
let SPHERE_SUBSET_CBALL = 
prove (`!x e. sphere(x,e) SUBSET cball(x,e)`,
REWRITE_TAC[IN_SPHERE; IN_CBALL; SUBSET] THEN REAL_ARITH_TAC);;
let SUBSET_BALL = 
prove (`!x d e. d <= e ==> ball(x,d) SUBSET ball(x,e)`,
REWRITE_TAC[SUBSET; IN_BALL] THEN MESON_TAC[REAL_LTE_TRANS]);;
let SUBSET_CBALL = 
prove (`!x d e. d <= e ==> cball(x,d) SUBSET cball(x,e)`,
REWRITE_TAC[SUBSET; IN_CBALL] THEN MESON_TAC[REAL_LE_TRANS]);;
let BALL_MAX_UNION = 
prove (`!a r s. ball(a,max r s) = ball(a,r) UNION ball(a,s)`,
REWRITE_TAC[IN_BALL; IN_UNION; EXTENSION] THEN REAL_ARITH_TAC);;
let BALL_MIN_INTER = 
prove (`!a r s. ball(a,min r s) = ball(a,r) INTER ball(a,s)`,
REWRITE_TAC[IN_BALL; IN_INTER; EXTENSION] THEN REAL_ARITH_TAC);;
let CBALL_MAX_UNION = 
prove (`!a r s. cball(a,max r s) = cball(a,r) UNION cball(a,s)`,
REWRITE_TAC[IN_CBALL; IN_UNION; EXTENSION] THEN REAL_ARITH_TAC);;
let CBALL_MIN_INTER = 
prove (`!x d e. cball(x,min d e) = cball(x,d) INTER cball(x,e)`,
REWRITE_TAC[EXTENSION; IN_INTER; IN_CBALL] THEN REAL_ARITH_TAC);;
let BALL_TRANSLATION = 
prove (`!a x r. ball(a + x,r) = IMAGE (\y. a + y) (ball(x,r))`,
REWRITE_TAC[ball] THEN GEOM_TRANSLATE_TAC[]);;
let CBALL_TRANSLATION = 
prove (`!a x r. cball(a + x,r) = IMAGE (\y. a + y) (cball(x,r))`,
REWRITE_TAC[cball] THEN GEOM_TRANSLATE_TAC[]);;
let SPHERE_TRANSLATION = 
prove (`!a x r. sphere(a + x,r) = IMAGE (\y. a + y) (sphere(x,r))`,
REWRITE_TAC[sphere] THEN GEOM_TRANSLATE_TAC[]);;
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];;
let BALL_SCALING = 
prove (`!c. &0 < c ==> !x r. ball(c % x,c * r) = IMAGE (\x. c % x) (ball(x,r))`,
REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_MESON_TAC[SURJECTIVE_SCALING; REAL_LT_IMP_NZ]; ALL_TAC] THEN REWRITE_TAC[IN_BALL; DIST_MUL] THEN ASM_SIMP_TAC[REAL_ARITH `&0 < c ==> abs c = c`; REAL_LT_LMUL_EQ]);;
let CBALL_SCALING = 
prove (`!c. &0 < c ==> !x r. cball(c % x,c * r) = IMAGE (\x. c % x) (cball(x,r))`,
REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_MESON_TAC[SURJECTIVE_SCALING; REAL_LT_IMP_NZ]; ALL_TAC] THEN REWRITE_TAC[IN_CBALL; DIST_MUL] THEN ASM_SIMP_TAC[REAL_ARITH `&0 < c ==> abs c = c`; REAL_LE_LMUL_EQ]);;
add_scaling_theorems [BALL_SCALING; CBALL_SCALING];;
let CBALL_DIFF_BALL = 
prove (`!a r. cball(a,r) DIFF ball(a,r) = sphere(a,r)`,
REWRITE_TAC[ball; cball; sphere; EXTENSION; IN_DIFF; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
let BALL_UNION_SPHERE = 
prove (`!a r. ball(a,r) UNION sphere(a,r) = cball(a,r)`,
REWRITE_TAC[ball; cball; sphere; EXTENSION; IN_UNION; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
let SPHERE_UNION_BALL = 
prove (`!a r. sphere(a,r) UNION ball(a,r) = cball(a,r)`,
REWRITE_TAC[ball; cball; sphere; EXTENSION; IN_UNION; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
let CBALL_DIFF_SPHERE = 
prove (`!a r. cball(a,r) DIFF sphere(a,r) = ball(a,r)`,
REWRITE_TAC[EXTENSION; IN_DIFF; IN_SPHERE; IN_BALL; IN_CBALL] THEN REAL_ARITH_TAC);;
let OPEN_CONTAINS_BALL_EQ = 
prove (`!s. open s ==> (!x. x IN s <=> ?e. &0 < e /\ ball(x,e) SUBSET s)`,
let BALL_EQ_EMPTY = 
prove (`!x e. (ball(x,e) = {}) <=> e <= &0`,
let BALL_EMPTY = 
prove (`!x e. e <= &0 ==> ball(x,e) = {}`,
REWRITE_TAC[BALL_EQ_EMPTY]);;
let OPEN_CONTAINS_CBALL = 
prove (`!s. open s <=> !x. x IN s ==> ?e. &0 < e /\ cball(x,e) SUBSET s`,
GEN_TAC THEN REWRITE_TAC[OPEN_CONTAINS_BALL] THEN EQ_TAC THENL [ALL_TAC; ASM_MESON_TAC[SUBSET_TRANS; BALL_SUBSET_CBALL]] THEN MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL] THEN DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN EXISTS_TAC `e / &2` THEN ASM_REWRITE_TAC[REAL_HALF] THEN SUBGOAL_THEN `e / &2 < e` (fun th -> ASM_MESON_TAC[th; REAL_LET_TRANS]) THEN ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN UNDISCH_TAC `&0 < e` THEN REAL_ARITH_TAC);;
let OPEN_CONTAINS_CBALL_EQ = 
prove (`!s. open s ==> (!x. x IN s <=> ?e. &0 < e /\ cball(x,e) SUBSET s)`,
let SPHERE_EQ_EMPTY = 
prove (`!a:real^N r. sphere(a,r) = {} <=> r < &0`,
REWRITE_TAC[sphere; EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY] THEN REPEAT GEN_TAC THEN EQ_TAC THENL [ALL_TAC; CONV_TAC NORM_ARITH] THEN MESON_TAC[VECTOR_CHOOSE_DIST; REAL_NOT_LE]);;
let SPHERE_EMPTY = 
prove (`!a:real^N r. r < &0 ==> sphere(a,r) = {}`,
REWRITE_TAC[SPHERE_EQ_EMPTY]);;
let NEGATIONS_BALL = 
prove (`!r. IMAGE (--) (ball(vec 0:real^N,r)) = ball(vec 0,r)`,
GEN_TAC THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN REWRITE_TAC[IN_BALL_0; NORM_NEG] THEN MESON_TAC[VECTOR_NEG_NEG]);;
let NEGATIONS_CBALL = 
prove (`!r. IMAGE (--) (cball(vec 0:real^N,r)) = cball(vec 0,r)`,
GEN_TAC THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN REWRITE_TAC[IN_CBALL_0; NORM_NEG] THEN MESON_TAC[VECTOR_NEG_NEG]);;
let NEGATIONS_SPHERE = 
prove (`!r. IMAGE (--) (sphere(vec 0:real^N,r)) = sphere(vec 0,r)`,
GEN_TAC THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN REWRITE_TAC[IN_SPHERE_0; NORM_NEG] THEN MESON_TAC[VECTOR_NEG_NEG]);;
let ORTHOGONAL_TRANSFORMATION_BALL = 
prove (`!f:real^N->real^N r. orthogonal_transformation f ==> IMAGE f (ball(vec 0,r)) = ball(vec 0,r)`,
let ORTHOGONAL_TRANSFORMATION_CBALL = 
prove (`!f:real^N->real^N r. orthogonal_transformation f ==> IMAGE f (cball(vec 0,r)) = cball(vec 0,r)`,
let ORTHOGONAL_TRANSFORMATION_SPHERE = 
prove (`!f:real^N->real^N r. orthogonal_transformation f ==> IMAGE f (sphere(vec 0,r)) = sphere(vec 0,r)`,
(* ------------------------------------------------------------------------- *) (* Also some invariance theorems for relative topology. *) (* ------------------------------------------------------------------------- *)
let OPEN_IN_TRANSLATION_EQ = 
prove (`!a s t. open_in (subtopology euclidean (IMAGE (\x. a + x) t)) (IMAGE (\x. a + x) s) <=> open_in (subtopology euclidean t) s`,
REWRITE_TAC[open_in] THEN GEOM_TRANSLATE_TAC[]);;
add_translation_invariants [OPEN_IN_TRANSLATION_EQ];;
let CLOSED_IN_TRANSLATION_EQ = 
prove (`!a s t. closed_in (subtopology euclidean (IMAGE (\x. a + x) t)) (IMAGE (\x. a + x) s) <=> closed_in (subtopology euclidean t) s`,
REWRITE_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN GEOM_TRANSLATE_TAC[]);;
add_translation_invariants [CLOSED_IN_TRANSLATION_EQ];; (* ------------------------------------------------------------------------- *) (* Limit points. *) (* ------------------------------------------------------------------------- *)
let LIMPT_APPROACHABLE = 
prove (`!x s. x limit_point_of s <=> !e. &0 < e ==> ?x'. x' IN s /\ ~(x' = x) /\ dist(x',x) < e`,
REPEAT GEN_TAC THEN REWRITE_TAC[limit_point_of] THEN MESON_TAC[open_def; DIST_SYM; OPEN_BALL; CENTRE_IN_BALL; IN_BALL]);;
let LIMPT_APPROACHABLE_LE = 
prove (`!x s. x limit_point_of s <=> !e. &0 < e ==> ?x'. x' IN s /\ ~(x' = x) /\ dist(x',x) <= e`,
REPEAT GEN_TAC THEN REWRITE_TAC[LIMPT_APPROACHABLE] THEN MATCH_MP_TAC(TAUT `(~a <=> ~b) ==> (a <=> b)`) THEN REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; NOT_EXISTS_THM] THEN REWRITE_TAC[TAUT `~(a /\ b /\ c) <=> c ==> ~(a /\ b)`; APPROACHABLE_LT_LE]);;
let LIMPT_UNIV = 
prove (`!x:real^N. x limit_point_of UNIV`,
GEN_TAC THEN REWRITE_TAC[LIMPT_APPROACHABLE; IN_UNIV] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN SUBGOAL_THEN `?c:real^N. norm(c) = e / &2` CHOOSE_TAC THENL [ASM_SIMP_TAC[VECTOR_CHOOSE_SIZE; REAL_HALF; REAL_LT_IMP_LE]; ALL_TAC] THEN EXISTS_TAC `x + c:real^N` THEN REWRITE_TAC[dist; VECTOR_EQ_ADDR] THEN ASM_REWRITE_TAC[VECTOR_ADD_SUB] THEN SUBGOAL_THEN `&0 < e / &2 /\ e / &2 < e` (fun th -> ASM_MESON_TAC[th; NORM_0; REAL_LT_REFL]) THEN SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN UNDISCH_TAC `&0 < e` THEN REAL_ARITH_TAC);;
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 LIMIT_POINT_FINITE = 
prove (`!s a. FINITE s ==> ~(a limit_point_of s)`,
REWRITE_TAC[LIMPT_APPROACHABLE; GSYM REAL_NOT_LE] THEN REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; NOT_EXISTS_THM; REAL_NOT_LE; REAL_NOT_LT; TAUT `~(a /\ b /\ c) <=> a /\ b ==> ~c`] THEN MESON_TAC[FINITE_SET_AVOID; DIST_SYM]);;
let LIMPT_SING = 
prove (`!x y:real^N. ~(x limit_point_of {y})`,
let LIMPT_INSERT = 
prove (`!s x y:real^N. x limit_point_of (y INSERT s) <=> x limit_point_of s`,
ONCE_REWRITE_TAC[SET_RULE `y INSERT s = {y} UNION s`] THEN REWRITE_TAC[LIMIT_POINT_UNION] THEN SIMP_TAC[FINITE_SING; LIMIT_POINT_FINITE]);;
let LIMPT_OF_LIMPTS = 
prove (`!x:real^N s. x limit_point_of {y | y limit_point_of s} ==> x limit_point_of s`,
REWRITE_TAC[LIMPT_APPROACHABLE; IN_ELIM_THM] THEN REPEAT GEN_TAC 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 `dist(y:real^N,x)`) THEN ASM_SIMP_TAC[DIST_POS_LT] THEN MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC);;
let CLOSED_LIMPTS = 
prove (`!s. closed {x:real^N | x limit_point_of s}`,
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_UNIV = 
prove (`!x. x limit_point_of (:real^N)`,
GEN_TAC THEN REWRITE_TAC[LIMPT_APPROACHABLE; IN_UNIV] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN MP_TAC(ISPECL [`x:real^N`; `e / &2`] VECTOR_CHOOSE_DIST) THEN ANTS_TAC THENL [ASM_REAL_ARITH_TAC; MATCH_MP_TAC MONO_EXISTS] THEN POP_ASSUM MP_TAC THEN CONV_TAC NORM_ARITH);;
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);;
let LIMPT_OF_OPEN = 
prove (`!s x:real^N. open s /\ x IN s ==> x limit_point_of s`,
REWRITE_TAC[OPEN_IN] THEN ONCE_REWRITE_TAC[GSYM SUBTOPOLOGY_UNIV] THEN MESON_TAC[LIMPT_OF_OPEN_IN; LIMPT_OF_UNIV]);;
let OPEN_IN_SING = 
prove (`!s a. open_in (subtopology euclidean s) {a} <=> a IN s /\ ~(a limit_point_of s)`,
REWRITE_TAC[open_in; LIMPT_APPROACHABLE; SING_SUBSET; IN_SING] THEN REWRITE_TAC[FORALL_UNWIND_THM2] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Interior of a set. *) (* ------------------------------------------------------------------------- *)
let INTERIOR_LIMIT_POINT = 
prove (`!s x:real^N. x IN interior s ==> x limit_point_of s`,
REPEAT GEN_TAC THEN REWRITE_TAC[IN_INTERIOR; IN_ELIM_THM; SUBSET; IN_BALL] THEN DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN REWRITE_TAC[LIMPT_APPROACHABLE] THEN X_GEN_TAC `d:real` THEN DISCH_TAC THEN MP_TAC(ISPECL [`x:real^N`; `min d e / &2`] VECTOR_CHOOSE_DIST) THEN ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN REPEAT CONJ_TAC THENL [FIRST_X_ASSUM MATCH_MP_TAC; CONV_TAC (RAND_CONV SYM_CONV) THEN REWRITE_TAC[GSYM DIST_EQ_0]; ONCE_REWRITE_TAC[DIST_SYM]] THEN ASM_REAL_ARITH_TAC);;
let INTERIOR_SING = 
prove (`!a:real^N. interior {a} = {}`,
REWRITE_TAC[EXTENSION; NOT_IN_EMPTY] THEN MESON_TAC[INTERIOR_LIMIT_POINT; LIMPT_SING]);;
(* ------------------------------------------------------------------------- *) (* Closure of a set. *) (* ------------------------------------------------------------------------- *)
let LIMPT_OF_CLOSURE = 
prove (`!x:real^N s. x limit_point_of closure s <=> x limit_point_of s`,
REWRITE_TAC[closure; IN_UNION; IN_ELIM_THM; LIMIT_POINT_UNION] THEN REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT `(q ==> p) ==> (p \/ q <=> p)`) THEN REWRITE_TAC[LIMPT_OF_LIMPTS]);;
(* ------------------------------------------------------------------------- *) (* 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`,
MESON_TAC[NET]);;
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)`,
MESON_TAC[NET]);;
(* ------------------------------------------------------------------------- *) (* Common nets and the "within" modifier for nets. *) (* ------------------------------------------------------------------------- *) parse_as_infix("within",(14,"right"));; parse_as_infix("in_direction",(14,"right"));;
let at = new_definition
  `at a = mk_net(\x y. &0 < dist(x,a) /\ dist(x,a) <= dist(y,a))`;;
let at_infinity = new_definition
  `at_infinity = mk_net(\x y. norm(x) >= norm(y))`;;
let sequentially = new_definition
  `sequentially = mk_net(\m:num n. m >= n)`;;
let within = new_definition
  `net within s = mk_net(\x y. netord net x y /\ x IN s)`;;
let in_direction = new_definition
  `a in_direction v = (at a) within {b | ?c. &0 <= c /\ (b - a = c % v)}`;;
(* ------------------------------------------------------------------------- *) (* 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)`,
GEN_TAC THEN NET_PROVE_TAC[at] THEN MESON_TAC[REAL_LE_TOTAL; REAL_LE_REFL; REAL_LE_TRANS; REAL_LET_TRANS]);;
let AT_INFINITY = 
prove (`!x y. netord at_infinity x y <=> norm(x) >= norm(y)`,
NET_PROVE_TAC[at_infinity] THEN REWRITE_TAC[real_ge; REAL_LE_REFL] THEN MESON_TAC[REAL_LE_TOTAL; REAL_LE_REFL; REAL_LE_TRANS]);;
let SEQUENTIALLY = 
prove (`!m n. netord sequentially m n <=> m >= n`,
NET_PROVE_TAC[sequentially] THEN REWRITE_TAC[GE; LE_REFL] THEN MESON_TAC[LE_CASES; LE_REFL; LE_TRANS]);;
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]);;
let IN_DIRECTION = 
prove (`!a v x y. netord(a in_direction v) x y <=> &0 < dist(x,a) /\ dist(x,a) <= dist(y,a) /\ ?c. &0 <= c /\ (x - a = c % v)`,
let WITHIN_UNIV = 
prove (`!x:real^N. at x within UNIV = at x`,
REWRITE_TAC[within; at; IN_UNIV] THEN REWRITE_TAC[ETA_AX; net_tybij]);;
let WITHIN_WITHIN = 
prove (`!net s t. (net within s) within t = net within (s INTER t)`,
ONCE_REWRITE_TAC[within] THEN REWRITE_TAC[WITHIN; IN_INTER; GSYM CONJ_ASSOC]);;
(* ------------------------------------------------------------------------- *) (* Identify trivial limits, where we can't approach arbitrarily closely. *) (* ------------------------------------------------------------------------- *)
let trivial_limit = new_definition
  `trivial_limit net <=>
     (!a:A b. a = b) \/
     ?a:A b. ~(a = b) /\ !x. ~(netord(net) x a) /\ ~(netord(net) x b)`;;
let TRIVIAL_LIMIT_WITHIN = 
prove (`!a:real^N. trivial_limit (at a within s) <=> ~(a limit_point_of s)`,
REWRITE_TAC[trivial_limit; LIMPT_APPROACHABLE_LE; WITHIN; AT; DIST_NZ] THEN REPEAT GEN_TAC THEN EQ_TAC THENL [DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL [MESON_TAC[REAL_LT_01; REAL_LT_REFL; VECTOR_CHOOSE_DIST; DIST_REFL; REAL_LT_IMP_LE]; DISCH_THEN(X_CHOOSE_THEN `b:real^N` (X_CHOOSE_THEN `c:real^N` STRIP_ASSUME_TAC)) THEN SUBGOAL_THEN `&0 < dist(a,b:real^N) \/ &0 < dist(a,c:real^N)` MP_TAC THEN ASM_MESON_TAC[DIST_TRIANGLE; DIST_SYM; GSYM DIST_NZ; GSYM DIST_EQ_0; REAL_ARITH `x <= &0 + &0 ==> ~(&0 < x)`]]; REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN DISJ2_TAC THEN EXISTS_TAC `a:real^N` THEN SUBGOAL_THEN `?b:real^N. dist(a,b) = e` MP_TAC THENL [ASM_SIMP_TAC[VECTOR_CHOOSE_DIST; REAL_LT_IMP_LE]; ALL_TAC] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:real^N` THEN DISCH_THEN(SUBST_ALL_TAC o SYM) THEN ASM_MESON_TAC[REAL_NOT_LE; DIST_REFL; DIST_NZ; DIST_SYM]]);;
let TRIVIAL_LIMIT_AT = 
prove (`!a. ~(trivial_limit (at a))`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN REWRITE_TAC[TRIVIAL_LIMIT_WITHIN; LIMPT_UNIV]);;
let TRIVIAL_LIMIT_AT_INFINITY = 
prove (`~(trivial_limit at_infinity)`,
let TRIVIAL_LIMIT_SEQUENTIALLY = 
prove (`~(trivial_limit sequentially)`,
REWRITE_TAC[trivial_limit; SEQUENTIALLY] THEN MESON_TAC[GE_REFL; NOT_SUC]);;
let LIM_WITHIN_CLOSED_TRIVIAL = 
prove (`!a s. closed s /\ ~(a IN s) ==> trivial_limit (at a within s)`,
REWRITE_TAC[TRIVIAL_LIMIT_WITHIN] THEN MESON_TAC[CLOSED_LIMPT]);;
let NONTRIVIAL_LIMIT_WITHIN = 
prove (`!net s. trivial_limit net ==> trivial_limit(net within s)`,
REWRITE_TAC[trivial_limit; WITHIN] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Some property holds "sufficiently close" to the limit point. *) (* ------------------------------------------------------------------------- *)
let eventually = new_definition
 `eventually p net <=>
        trivial_limit net \/
        ?y. (?x. netord net x y) /\ (!x. netord net x y ==> p x)`;;
let EVENTUALLY_HAPPENS = 
prove (`!net p. eventually p net ==> trivial_limit net \/ ?x. p x`,
REWRITE_TAC[eventually] THEN MESON_TAC[]);;
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)`,
REWRITE_TAC[eventually; AT; WITHIN; TRIVIAL_LIMIT_WITHIN] THEN REWRITE_TAC[LIMPT_APPROACHABLE_LE; DIST_NZ] THEN REPEAT GEN_TAC THEN EQ_TAC THENL [MESON_TAC[REAL_LTE_TRANS]; ALL_TAC] THEN DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN MATCH_MP_TAC(TAUT `(a ==> b) ==> ~a \/ b`) THEN DISCH_TAC THEN SUBGOAL_THEN `?b:real^M. dist(a,b) = d` MP_TAC THENL [ASM_SIMP_TAC[VECTOR_CHOOSE_DIST; REAL_LT_IMP_LE]; ALL_TAC] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:real^M` THEN DISCH_THEN(SUBST_ALL_TAC o SYM) THEN ASM_MESON_TAC[REAL_NOT_LE; DIST_REFL; DIST_NZ; DIST_SYM]);;
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)`,
REWRITE_TAC[EVENTUALLY_WITHIN_LE] THEN ONCE_REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> c ==> a /\ b ==> d`] THEN REWRITE_TAC[APPROACHABLE_LT_LE]);;
let EVENTUALLY_AT = 
prove (`!a p. eventually p (at a) <=> ?d. &0 < d /\ !x. &0 < dist(x,a) /\ dist(x,a) < d ==> p(x)`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN REWRITE_TAC[EVENTUALLY_WITHIN; IN_UNIV]);;
let EVENTUALLY_SEQUENTIALLY = 
prove (`!p. eventually p sequentially <=> ?N. !n. N <= n ==> p n`,
REWRITE_TAC[eventually; SEQUENTIALLY; GE; LE_REFL; TRIVIAL_LIMIT_SEQUENTIALLY] THEN MESON_TAC[LE_REFL]);;
let EVENTUALLY_AT_INFINITY = 
prove (`!p. eventually p at_infinity <=> ?b. !x. norm(x) >= b ==> p x`,
REWRITE_TAC[eventually; AT_INFINITY; TRIVIAL_LIMIT_AT_INFINITY] THEN REPEAT GEN_TAC THEN EQ_TAC THENL [MESON_TAC[REAL_LE_REFL]; ALL_TAC] THEN MESON_TAC[real_ge; REAL_LE_REFL; VECTOR_CHOOSE_SIZE; REAL_ARITH `&0 <= b \/ (!x. x >= &0 ==> x >= b)`]);;
let EVENTUALLY_AT_INFINITY_POS = 
prove (`!p:real^N->bool. eventually p at_infinity <=> ?b. &0 < b /\ !x. norm x >= b ==> p x`,
GEN_TAC THEN REWRITE_TAC[EVENTUALLY_AT_INFINITY; real_ge] THEN MESON_TAC[REAL_ARITH `&0 < abs b + &1 /\ (abs b + &1 <= x ==> b <= x)`]);;
let ALWAYS_EVENTUALLY = 
prove (`(!x. p x) ==> eventually p net`,
REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[eventually; trivial_limit] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *) (* 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[]);;
let EVENTUALLY_FALSE = 
prove (`!net. eventually (\x. F) net <=> trivial_limit net`,
REWRITE_TAC[eventually] THEN MESON_TAC[]);;
let EVENTUALLY_TRUE = 
prove (`!net. eventually (\x. T) net <=> T`,
REWRITE_TAC[eventually; trivial_limit] THEN MESON_TAC[]);;
let NOT_EVENTUALLY = 
prove (`!net p. (!x. ~(p x)) /\ ~(trivial_limit net) ==> ~(eventually p net)`,
REWRITE_TAC[eventually] THEN MESON_TAC[]);;
let EVENTUALLY_FORALL = 
prove (`!net:(A net) p s:B->bool. FINITE s /\ ~(s = {}) ==> (eventually (\x. !a. a IN s ==> p a x) net <=> !a. a IN s ==> eventually (p a) net)`,
GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[FORALL_IN_INSERT; EVENTUALLY_AND; ETA_AX] THEN MAP_EVERY X_GEN_TAC [`b:B`; `t:B->bool`] THEN ASM_CASES_TAC `t:B->bool = {}` THEN ASM_SIMP_TAC[NOT_IN_EMPTY; EVENTUALLY_TRUE]);;
let FORALL_EVENTUALLY = 
prove (`!net:(A net) p s:B->bool. FINITE s /\ ~(s = {}) ==> ((!a. a IN s ==> eventually (p a) net) <=> eventually (\x. !a. a IN s ==> p a x) net)`,
SIMP_TAC[EVENTUALLY_FORALL]);;
(* ------------------------------------------------------------------------- *) (* Limits, defined as vacuously true when the limit is trivial. *) (* ------------------------------------------------------------------------- *) parse_as_infix("-->",(12,"right"));;
let tendsto = new_definition
  `(f --> l) net <=> !e. &0 < e ==> eventually (\x. dist(f(x),l) < e) net`;;
let lim = new_definition
 `lim net f = @l. (f --> l) net`;;
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`,
REWRITE_TAC[tendsto; EVENTUALLY_WITHIN_LE]);;
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`,
REWRITE_TAC[tendsto; EVENTUALLY_WITHIN] THEN MESON_TAC[]);;
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`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN REWRITE_TAC[LIM_WITHIN_LE; IN_UNIV]);;
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`,
REWRITE_TAC[tendsto; EVENTUALLY_AT] THEN MESON_TAC[]);;
let LIM_AT_INFINITY = 
prove (`!f l. (f --> l) at_infinity <=> !e. &0 < e ==> ?b. !x. norm(x) >= b ==> dist(f(x),l) < e`,
REWRITE_TAC[tendsto; EVENTUALLY_AT_INFINITY] THEN MESON_TAC[]);;
let LIM_AT_INFINITY_POS = 
prove (`!f l. (f --> l) at_infinity <=> !e. &0 < e ==> ?b. &0 < b /\ !x. norm x >= b ==> dist(f x,l) < e`,
REPEAT GEN_TAC THEN REWRITE_TAC[LIM_AT_INFINITY] THEN MESON_TAC[REAL_ARITH `&0 < abs b + &1 /\ (x >= abs b + &1 ==> x >= b)`]);;
let LIM_SEQUENTIALLY = 
prove (`!s l. (s --> l) sequentially <=> !e. &0 < e ==> ?N. !n. N <= n ==> dist(s(n),l) < e`,
REWRITE_TAC[tendsto; EVENTUALLY_SEQUENTIALLY] THEN MESON_TAC[]);;
let LIM_EVENTUALLY = 
prove (`!net f l. eventually (\x. f x = l) net ==> (f --> l) net`,
REWRITE_TAC[eventually; LIM] THEN MESON_TAC[DIST_REFL]);;
(* ------------------------------------------------------------------------- *) (* The expected monotonicity property. *) (* ------------------------------------------------------------------------- *)
let LIM_WITHIN_EMPTY = 
prove (`!f l x. (f --> l) (at x within {})`,
REWRITE_TAC[LIM_WITHIN; NOT_IN_EMPTY] THEN MESON_TAC[REAL_LT_01]);;
let LIM_WITHIN_SUBSET = 
prove (`!f l a s. (f --> l) (at a within s) /\ t SUBSET s ==> (f --> l) (at a within t)`,
REWRITE_TAC[LIM_WITHIN; SUBSET] THEN MESON_TAC[]);;
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)`,
MESON_TAC[LIM_UNION; WITHIN_UNIV]);;
(* ------------------------------------------------------------------------- *) (* 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`,
REPEAT GEN_TAC THEN REWRITE_TAC[tendsto; CONJ_ASSOC] THEN ONCE_REWRITE_TAC[LEFT_AND_FORALL_THM] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN REWRITE_TAC[EVENTUALLY_WITHIN; GSYM DIST_NZ; o_DEF] THEN DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN FIRST_X_ASSUM(MP_TAC o SPEC `d:real`) THEN ASM_REWRITE_TAC[GSYM EVENTUALLY_AND] THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN ASM_MESON_TAC[DIST_REFL]);;
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_AT_WITHIN = 
prove (`!f l a s. (f --> l)(at a) ==> (f --> l)(at a within s)`,
REWRITE_TAC[LIM_AT; LIM_WITHIN] THEN MESON_TAC[]);;
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_SEQUENTIAL_INJ = 
prove (`!x:real^N s. x limit_point_of s <=> ?f. (!n. f(n) IN (s DELETE x)) /\ (!m n. f m = f n <=> m = n) /\ (f --> x) sequentially`,
REPEAT GEN_TAC THEN REWRITE_TAC[LIMPT_APPROACHABLE; LIM_SEQUENTIALLY; IN_DELETE] THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[GE; LE_REFL]] 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 `y:real->real^N` THEN DISCH_TAC THEN (STRIP_ASSUME_TAC o prove_recursive_functions_exist num_RECURSION) `(z 0 = y (&1)) /\ (!n. z (SUC n):real^N = y(min (inv(&2 pow (SUC n))) (dist(z n,x))))` THEN EXISTS_TAC `z:num->real^N` THEN SUBGOAL_THEN `!n. z(n) IN s /\ ~(z n:real^N = x) /\ dist(z n,x) < inv(&2 pow n)` ASSUME_TAC THENL [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_SIMP_TAC[REAL_LT_01] THEN FIRST_X_ASSUM(MP_TAC o SPEC `min (inv(&2 pow (SUC n))) (dist(z n:real^N,x))`) THEN ASM_SIMP_TAC[REAL_LT_MIN; REAL_LT_INV_EQ; REAL_LT_POW2; DIST_POS_LT]; ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [MATCH_MP_TAC WLOG_LT THEN REWRITE_TAC[EQ_SYM_EQ] THEN SUBGOAL_THEN `!m n:num. m < n ==> dist(z n:real^N,x) < dist(z m,x)` (fun th -> MESON_TAC[th; REAL_LT_REFL; LT_REFL]) THEN MATCH_MP_TAC TRANSITIVE_STEPWISE_LT THEN CONJ_TAC THENL [REAL_ARITH_TAC; GEN_TAC THEN ASM_REWRITE_TAC[]] THEN FIRST_X_ASSUM(MP_TAC o SPEC `min (inv(&2 pow (SUC n))) (dist(z n:real^N,x))`) THEN ASM_SIMP_TAC[REAL_LT_MIN; REAL_LT_INV_EQ; REAL_LT_POW2; DIST_POS_LT]; X_GEN_TAC `e:real` THEN DISCH_TAC THEN MP_TAC(ISPECL [`inv(&2)`; `e:real`] REAL_ARCH_POW_INV) THEN ANTS_TAC THENL [ASM_REAL_ARITH_TAC; MATCH_MP_TAC MONO_EXISTS] THEN X_GEN_TAC `N:num` THEN REWRITE_TAC[REAL_POW_INV] THEN DISCH_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] REAL_LT_TRANS)) THEN MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `inv(&2 pow n)` THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_INV2 THEN ASM_REWRITE_TAC[REAL_LT_POW2] THEN MATCH_MP_TAC REAL_POW_MONO THEN REWRITE_TAC[REAL_OF_NUM_LE] THEN ASM_ARITH_TAC]]);;
let LIMPT_SEQUENTIAL = 
prove (`!x:real^N s. x limit_point_of s <=> ?f. (!n. f(n) IN (s DELETE x)) /\ (f --> x) sequentially`,
REPEAT GEN_TAC THEN EQ_TAC THENL [REWRITE_TAC[LIMPT_SEQUENTIAL_INJ] THEN MESON_TAC[]; REWRITE_TAC[LIMPT_APPROACHABLE; LIM_SEQUENTIALLY; IN_DELETE] THEN MESON_TAC[GE; LE_REFL]]);;
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_of = new_definition
 `x condensation_point_of s <=>
        !t. x IN t /\ open t ==> ~COUNTABLE(s INTER t)`;;
let CONDENSATION_POINT_OF_SUBSET = 
prove (`!x:real^N s t. x condensation_point_of s /\ s SUBSET t ==> x condensation_point_of t`,
REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN REWRITE_TAC[condensation_point_of] THEN MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[CONTRAPOS_THM] THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] COUNTABLE_SUBSET) THEN ASM SET_TAC[]);;
let CONDENSATION_POINT_IMP_LIMPT = 
prove (`!x s. x condensation_point_of s ==> x limit_point_of s`,
REWRITE_TAC[condensation_point_of; LIMPT_INFINITE_OPEN; INFINITE] THEN MESON_TAC[FINITE_IMP_COUNTABLE]);;
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`,
REPEAT GEN_TAC THEN REWRITE_TAC[LIM] THEN ASM_CASES_TAC `trivial_limit (net:(A)net)` THEN ASM_REWRITE_TAC[] THEN STRIP_TAC THEN FIRST_ASSUM(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC o MATCH_MP LINEAR_BOUNDED_POS) THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / B`) THEN ASM_SIMP_TAC[REAL_LT_DIV; dist; GSYM LINEAR_SUB; REAL_LT_RDIV_EQ] THEN ASM_MESON_TAC[REAL_LET_TRANS; REAL_MUL_SYM]);;
let LIM_CONST = 
prove (`!net a:real^N. ((\x. a) --> a) net`,
SIMP_TAC[LIM; DIST_REFL; trivial_limit] THEN MESON_TAC[]);;
let LIM_CMUL = 
prove (`!f l c. (f --> l) net ==> ((\x. c % f x) --> c % l) net`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_LINEAR THEN ASM_REWRITE_TAC[REWRITE_RULE[ETA_AX] (MATCH_MP LINEAR_COMPOSE_CMUL LINEAR_ID)]);;
let LIM_CMUL_EQ = 
prove (`!net f l c. ~(c = &0) ==> (((\x. c % f x) --> c % l) net <=> (f --> l) net)`,
REPEAT STRIP_TAC THEN EQ_TAC THEN SIMP_TAC[LIM_CMUL] THEN DISCH_THEN(MP_TAC o SPEC `inv c:real` o MATCH_MP LIM_CMUL) THEN ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID; ETA_AX]);;
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`,
REPEAT GEN_TAC THEN REWRITE_TAC[LIM] THEN ASM_CASES_TAC `trivial_limit (net:(A)net)` THEN ASM_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 MESON_TAC[REAL_HALF; DIST_TRIANGLE_ADD; REAL_LT_ADD2; REAL_LET_TRANS]);;
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`,
REWRITE_TAC[real_sub; VECTOR_SUB] THEN ASM_SIMP_TAC[LIM_ADD; LIM_NEG]);;
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`,
REPEAT GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP LIM_ADD) THEN FIRST_ASSUM(MP_TAC o MATCH_MP LIM_SUB) THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_ABS) THEN REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_ADD) THEN DISCH_THEN(MP_TAC o SPEC `inv(&2)` o MATCH_MP LIM_CMUL) THEN MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN BINOP_TAC THEN SIMP_TAC[FUN_EQ_THM; CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VECTOR_SUB_COMPONENT; LAMBDA_BETA] THEN REAL_ARITH_TAC);;
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`,
REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN(MP_TAC o MATCH_MP LIM_NEG)) THEN REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_NEG o MATCH_MP LIM_MAX) THEN MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN BINOP_TAC THEN SIMP_TAC[FUN_EQ_THM; CART_EQ; LAMBDA_BETA; VECTOR_NEG_COMPONENT] THEN REAL_ARITH_TAC);;
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`,
REWRITE_TAC[LIM; dist; VECTOR_SUB_RZERO]);;
let LIM_NULL_NORM = 
prove (`!net f. (f --> vec 0) net <=> ((\x. lift(norm(f x))) --> vec 0) net`,
REWRITE_TAC[LIM; dist; VECTOR_SUB_RZERO; REAL_ABS_NORM; NORM_LIFT]);;
let LIM_NULL_CMUL_EQ = 
prove (`!net f c. ~(c = &0) ==> (((\x. c % f x) --> vec 0) net <=> (f --> vec 0) net)`,
let LIM_NULL_CMUL = 
prove (`!net f c. (f --> vec 0) net ==> ((\x. c % f x) --> vec 0) net`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `c = &0` THEN ASM_SIMP_TAC[LIM_NULL_CMUL_EQ; VECTOR_MUL_LZERO; LIM_CONST]);;
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`,
REPEAT GEN_TAC THEN REWRITE_TAC[tendsto; RIGHT_AND_FORALL_THM] THEN MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[GSYM EVENTUALLY_AND] THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN REWRITE_TAC[dist; VECTOR_SUB_RZERO; NORM_LIFT] THEN REAL_ARITH_TAC);;
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`,
REWRITE_TAC[LIM; dist; GSYM LIFT_SUB; NORM_LIFT] THEN SIMP_TAC[GSYM VECTOR_SUB_COMPONENT] THEN MESON_TAC[COMPONENT_LE_NORM; REAL_LET_TRANS]);;
let LIM_TRANSFORM_BOUND = 
prove (`!f g. eventually (\n. norm(f n) <= norm(g n)) net /\ (g --> vec 0) net ==> (f --> vec 0) net`,
REPEAT GEN_TAC THEN REWRITE_TAC[tendsto; RIGHT_AND_FORALL_THM] THEN MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[GSYM EVENTUALLY_AND] THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN REWRITE_TAC[dist; VECTOR_SUB_RZERO] THEN REAL_ARITH_TAC);;
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`,
REPEAT GEN_TAC THEN REWRITE_TAC[tendsto] THEN STRIP_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / (abs B + &1)`) THEN ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < abs x + &1`] THEN UNDISCH_TAC `eventually (\a. g a:real^N = vec 0 \/ abs(f a) <= B) (net:(A net))` THEN REWRITE_TAC[IMP_IMP; GSYM EVENTUALLY_AND] THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MP) THEN REWRITE_TAC[dist; VECTOR_SUB_RZERO; o_THM; NORM_LIFT; NORM_MUL] THEN MATCH_MP_TAC ALWAYS_EVENTUALLY THEN X_GEN_TAC `x:A` THEN REWRITE_TAC[] THEN ASM_CASES_TAC `(g:A->real^N) x = vec 0` THEN ASM_REWRITE_TAC[NORM_0; REAL_MUL_RZERO] THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `B * e / (abs B + &1)` THEN ASM_SIMP_TAC[REAL_LE_MUL2; REAL_ABS_POS; NORM_POS_LE; REAL_LT_IMP_LE] THEN REWRITE_TAC[REAL_ARITH `c * (a / b) = (c * a) / b`] THEN SIMP_TAC[REAL_LT_LDIV_EQ; REAL_ARITH `&0 < abs x + &1`] THEN MATCH_MP_TAC(REAL_ARITH `e * B <= e * abs B /\ &0 < e ==> B * e < e * (abs B + &1)`) THEN ASM_SIMP_TAC[REAL_LE_LMUL_EQ] THEN REAL_ARITH_TAC);;
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`,
REPEAT GEN_TAC THEN REWRITE_TAC[tendsto] THEN STRIP_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / (abs B + &1)`) THEN ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < abs x + &1`] THEN UNDISCH_TAC `eventually(\a. f a = &0 \/ norm((g:A->real^N) a) <= B) net` THEN REWRITE_TAC[IMP_IMP; GSYM EVENTUALLY_AND] THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MP) THEN REWRITE_TAC[dist; VECTOR_SUB_RZERO; o_THM; NORM_LIFT; NORM_MUL] THEN MATCH_MP_TAC ALWAYS_EVENTUALLY THEN X_GEN_TAC `x:A` THEN REWRITE_TAC[] THEN ASM_CASES_TAC `(f:A->real) x = &0` THEN ASM_REWRITE_TAC[REAL_ABS_NUM; REAL_MUL_LZERO] THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `e / (abs B + &1) * B` THEN ASM_SIMP_TAC[REAL_LE_MUL2; REAL_ABS_POS; NORM_POS_LE; REAL_LT_IMP_LE] THEN REWRITE_TAC[REAL_ARITH `(a / b) * c = (a * c) / b`] THEN SIMP_TAC[REAL_LT_LDIV_EQ; REAL_ARITH `&0 < abs x + &1`] THEN MATCH_MP_TAC(REAL_ARITH `e * B <= e * abs B /\ &0 < e ==> e * B < e * (abs B + &1)`) THEN ASM_SIMP_TAC[REAL_LE_LMUL_EQ] THEN REAL_ARITH_TAC);;
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`,
GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[VSUM_CLAUSES; LIM_CONST; LIM_ADD; IN_INSERT; ETA_AX]);;
(* ------------------------------------------------------------------------- *) (* 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 TENDSTO_LIM = 
prove (`!net f l. ~(trivial_limit net) /\ (f --> l) net ==> lim net f = l`,
REWRITE_TAC[lim] THEN MESON_TAC[LIM_UNIQUE]);;
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_WITHIN_ID = 
prove (`!a s. ((\x. x) --> a) (at a within s)`,
REWRITE_TAC[LIM_WITHIN] THEN MESON_TAC[]);;
let LIM_AT_ID = 
prove (`!a. ((\x. x) --> a) (at a)`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN REWRITE_TAC[LIM_WITHIN_ID]);;
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. *) (* ------------------------------------------------------------------------- *)
let netlimit = new_definition
  `netlimit net = @a. !x. ~(netord net x a)`;;
let NETLIMIT_WITHIN = 
prove (`!a:real^N s. ~(trivial_limit (at a within s)) ==> (netlimit (at a within s) = a)`,
REWRITE_TAC[trivial_limit; netlimit; AT; WITHIN; DE_MORGAN_THM] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC SELECT_UNIQUE THEN REWRITE_TAC[] THEN SUBGOAL_THEN `!x:real^N. ~(&0 < dist(x,a) /\ dist(x,a) <= dist(a,a) /\ x IN s)` ASSUME_TAC THENL [ASM_MESON_TAC[DIST_REFL; REAL_NOT_LT]; ASM_MESON_TAC[]]);;
let NETLIMIT_AT = 
prove (`!a. netlimit(at a) = a`,
GEN_TAC THEN ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN MATCH_MP_TAC NETLIMIT_WITHIN THEN SIMP_TAC[TRIVIAL_LIMIT_AT; WITHIN_UNIV]);;
(* ------------------------------------------------------------------------- *) (* 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_EVENTUALLY = 
prove (`!net f g l. eventually (\x. f x = g x) net /\ (f --> l) net ==> (g --> l) net`,
REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o MATCH_MP LIM_EVENTUALLY) MP_TAC) THEN MESON_TAC[LIM_TRANSFORM]);;
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)`,
REPEAT GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN DISCH_TAC THEN DISCH_TAC THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LIM_TRANSFORM) THEN REWRITE_TAC[LIM_WITHIN] THEN REPEAT STRIP_TAC THEN EXISTS_TAC `d:real` THEN ASM_SIMP_TAC[VECTOR_SUB_REFL; DIST_REFL]);;
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)`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN MESON_TAC[LIM_TRANSFORM_WITHIN]);;
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)`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN MESON_TAC[LIM_TRANSFORM_AWAY_WITHIN]);;
(* ------------------------------------------------------------------------- *) (* Alternatively, within an open set. *) (* ------------------------------------------------------------------------- *)
let LIM_TRANSFORM_WITHIN_OPEN = 
prove (`!f g:real^M->real^N s a l. open s /\ a IN s /\ (!x. x IN s /\ ~(x = a) ==> f x = g x) /\ (f --> l) (at a) ==> (g --> l) (at a)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_TRANSFORM_AT THEN EXISTS_TAC `f:real^M->real^N` THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN DISCH_THEN(MP_TAC o SPEC `a:real^M`) THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[SUBSET; IN_BALL] THEN ASM_MESON_TAC[DIST_NZ; DIST_SYM]);;
let LIM_TRANSFORM_WITHIN_OPEN_IN = 
prove (`!f g:real^M->real^N s t a l. open_in (subtopology euclidean t) s /\ a IN s /\ (!x. x IN s /\ ~(x = a) ==> f x = g x) /\ (f --> l) (at a within t) ==> (g --> l) (at a within t)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_TRANSFORM_WITHIN THEN EXISTS_TAC `f:real^M->real^N` THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_CONTAINS_BALL]) THEN DISCH_THEN(MP_TAC o SPEC `a:real^M` o CONJUNCT2) THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[SUBSET; IN_INTER; IN_BALL] THEN ASM_MESON_TAC[DIST_NZ; DIST_SYM]);;
(* ------------------------------------------------------------------------- *) (* Another quite common idiom of an explicit conditional in a sequence. *) (* ------------------------------------------------------------------------- *)
let LIM_CASES_FINITE_SEQUENTIALLY = 
prove (`!f g l. FINITE {n | P n} ==> (((\n. if P n then f n else g n) --> l) sequentially <=> (g --> l) sequentially)`,
REPEAT STRIP_TAC THEN EQ_TAC THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LIM_TRANSFORM_EVENTUALLY) THEN FIRST_ASSUM(MP_TAC o SPEC `\n:num. n` o MATCH_MP UPPER_BOUND_FINITE_SET) THEN REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `N:num` THEN DISCH_TAC THEN SIMP_TAC[EVENTUALLY_SEQUENTIALLY] THEN EXISTS_TAC `N + 1` THEN ASM_MESON_TAC[ARITH_RULE `~(x <= n /\ n + 1 <= x)`]);;
let LIM_CASES_COFINITE_SEQUENTIALLY = 
prove (`!f g l. FINITE {n | ~P n} ==> (((\n. if P n then f n else g n) --> l) sequentially <=> (f --> l) sequentially)`,
ONCE_REWRITE_TAC[TAUT `(if p then x else y) = (if ~p then y else x)`] THEN REWRITE_TAC[LIM_CASES_FINITE_SEQUENTIALLY]);;
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)))`,
REWRITE_TAC[LIM_WITHIN; GSYM DIST_NZ] THEN SIMP_TAC[]);;
let LIM_CONG_AT = 
prove (`(!x. ~(x = a) ==> f x = g x) ==> (((\x. f x) --> l) (at a) <=> ((g --> l) (at a)))`,
REWRITE_TAC[LIM_AT; GSYM DIST_NZ] THEN SIMP_TAC[]);;
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]);;
let CLOSED_CONTAINS_SEQUENTIAL_LIMIT = 
prove (`!s x l:real^N. closed s /\ (!n. x n IN s) /\ (x --> l) sequentially ==> l IN s`,
let CLOSED_SEQUENTIAL_LIMITS = 
prove (`!s. closed s <=> !x l. (!n. x(n) IN s) /\ (x --> l) sequentially ==> l IN s`,
let CLOSURE_APPROACHABLE = 
prove (`!x s. x IN closure(s) <=> !e. &0 < e ==> ?y. y IN s /\ dist(y,x) < e`,
REWRITE_TAC[closure; LIMPT_APPROACHABLE; IN_UNION; IN_ELIM_THM] THEN MESON_TAC[DIST_REFL]);;
let CLOSED_APPROACHABLE = 
prove (`!x s. closed s ==> ((!e. &0 < e ==> ?y. y IN s /\ dist(y,x) < e) <=> x IN s)`,
let IN_CLOSURE_DELETE = 
prove (`!s x:real^N. x IN closure(s DELETE x) <=> x limit_point_of s`,
(* ------------------------------------------------------------------------- *) (* 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`]);;
let SEQ_HARMONIC = 
prove (`((\n. lift(inv(&n))) --> vec 0) sequentially`,
REWRITE_TAC[LIM_SEQUENTIALLY] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_ASSUM(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [REAL_ARCH_INV]) THEN EXISTS_TAC `N:num` THEN REPEAT STRIP_TAC THEN REWRITE_TAC[dist; VECTOR_SUB_RZERO; NORM_LIFT] THEN ASM_REWRITE_TAC[REAL_ABS_INV; REAL_ABS_NUM] THEN MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&N)` THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_INV2 THEN ASM_REWRITE_TAC[REAL_OF_NUM_LT; REAL_OF_NUM_LE; LT_NZ]);;
(* ------------------------------------------------------------------------- *) (* More properties of closed balls. *) (* ------------------------------------------------------------------------- *)
let CLOSED_CBALL = 
prove (`!x:real^N e. closed(cball(x,e))`,
REWRITE_TAC[CLOSED_SEQUENTIAL_LIMITS; IN_CBALL; dist] THEN GEN_TAC THEN GEN_TAC THEN X_GEN_TAC `s:num->real^N` THEN X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN MATCH_MP_TAC(ISPEC `sequentially` LIM_NORM_UBOUND) THEN EXISTS_TAC `\n. x - (s:num->real^N) n` THEN REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; EVENTUALLY_SEQUENTIALLY] THEN ASM_SIMP_TAC[LIM_SUB; LIM_CONST; SEQUENTIALLY] THEN MESON_TAC[GE_REFL]);;
let IN_INTERIOR_CBALL = 
prove (`!x s. x IN interior s <=> ?e. &0 < e /\ cball(x,e) SUBSET s`,
let LIMPT_BALL = 
prove (`!x:real^N y e. y limit_point_of ball(x,e) <=> &0 < e /\ y IN cball(x,e)`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `&0 < e` THENL [ALL_TAC; ASM_MESON_TAC[LIMPT_EMPTY; REAL_NOT_LT; BALL_EQ_EMPTY]] THEN ASM_REWRITE_TAC[] THEN EQ_TAC THENL [MESON_TAC[CLOSED_CBALL; CLOSED_LIMPT; LIMPT_SUBSET; BALL_SUBSET_CBALL]; REWRITE_TAC[IN_CBALL; LIMPT_APPROACHABLE; IN_BALL]] THEN DISCH_TAC THEN X_GEN_TAC `d:real` THEN DISCH_TAC THEN ASM_CASES_TAC `y:real^N = x` THEN ASM_REWRITE_TAC[DIST_NZ] THENL [MP_TAC(SPECL [`d:real`; `e:real`] REAL_DOWN2) THEN ASM_REWRITE_TAC[] THEN GEN_MESON_TAC 0 40 1 [VECTOR_CHOOSE_DIST; DIST_SYM; REAL_LT_IMP_LE]; ALL_TAC] THEN MP_TAC(SPECL [`norm(y:real^N - x)`; `d:real`] REAL_DOWN2) THEN RULE_ASSUM_TAC(REWRITE_RULE[DIST_NZ; dist]) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN EXISTS_TAC `(y:real^N) - (k / dist(y,x)) % (y - x)` THEN REWRITE_TAC[dist; VECTOR_ARITH `(y - c % z) - y = --c % z`] THEN REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; REAL_ABS_NEG] THEN ASM_SIMP_TAC[REAL_DIV_RMUL; REAL_LT_IMP_NZ] THEN REWRITE_TAC[VECTOR_ARITH `x - (y - k % (y - x)) = (&1 - k) % (x - y)`] THEN ASM_SIMP_TAC[REAL_ARITH `&0 < k ==> &0 < abs k`; NORM_MUL] THEN ASM_SIMP_TAC[REAL_ARITH `&0 < k /\ k < d ==> abs k < d`] THEN MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `norm(x:real^N - y)` THEN ASM_REWRITE_TAC[] THEN GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN MATCH_MP_TAC REAL_LT_RMUL THEN CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[NORM_SUB]] THEN MATCH_MP_TAC(REAL_ARITH `&0 < k /\ k < &1 ==> abs(&1 - k) < &1`) THEN ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_MUL_LZERO; REAL_MUL_LID]);;
let CLOSURE_BALL = 
prove (`!x:real^N e. &0 < e ==> (closure(ball(x,e)) = cball(x,e))`,
SIMP_TAC[EXTENSION; closure; IN_ELIM_THM; IN_UNION; LIMPT_BALL] THEN REWRITE_TAC[IN_BALL; IN_CBALL] THEN REAL_ARITH_TAC);;
let INTERIOR_BALL = 
prove (`!a r. interior(ball(a,r)) = ball(a,r)`,
SIMP_TAC[INTERIOR_OPEN; OPEN_BALL]);;
let INTERIOR_CBALL = 
prove (`!x:real^N e. interior(cball(x,e)) = ball(x,e)`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `&0 <= e` THENL [ALL_TAC; SUBGOAL_THEN `cball(x:real^N,e) = {} /\ ball(x:real^N,e) = {}` (fun th -> REWRITE_TAC[th; INTERIOR_EMPTY]) THEN REWRITE_TAC[IN_BALL; IN_CBALL; EXTENSION; NOT_IN_EMPTY] THEN CONJ_TAC THEN X_GEN_TAC `y:real^N` THEN MP_TAC(ISPECL [`x:real^N`; `y:real^N`] DIST_POS_LE) THEN POP_ASSUM MP_TAC THEN REAL_ARITH_TAC] THEN MATCH_MP_TAC INTERIOR_UNIQUE THEN REWRITE_TAC[BALL_SUBSET_CBALL; OPEN_BALL] THEN X_GEN_TAC `t:real^N->bool` THEN SIMP_TAC[SUBSET; IN_CBALL; IN_BALL; REAL_LT_LE] THEN STRIP_TAC THEN X_GEN_TAC `z:real^N` THEN DISCH_TAC THEN DISCH_THEN(SUBST_ALL_TAC o SYM) THEN FIRST_X_ASSUM(MP_TAC o SPEC `z:real^N` o GEN_REWRITE_RULE I [open_def]) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `d:real` MP_TAC) THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_CASES_TAC `z:real^N = x` THENL [FIRST_X_ASSUM SUBST_ALL_TAC THEN FIRST_X_ASSUM(X_CHOOSE_TAC `k:real` o MATCH_MP REAL_DOWN) THEN SUBGOAL_THEN `?w:real^N. dist(w,x) = k` STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[VECTOR_CHOOSE_DIST; DIST_SYM; REAL_LT_IMP_LE]; ASM_MESON_TAC[REAL_NOT_LE; DIST_REFL; DIST_SYM]]; RULE_ASSUM_TAC(REWRITE_RULE[DIST_NZ]) THEN DISCH_THEN(MP_TAC o SPEC `z + ((d / &2) / dist(z,x)) % (z - x:real^N)`) THEN REWRITE_TAC[dist; VECTOR_ADD_SUB; NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; REAL_ABS_NUM] THEN ASM_SIMP_TAC[REAL_DIV_RMUL; GSYM dist; REAL_LT_IMP_NZ] THEN ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN ASM_REWRITE_TAC[REAL_ARITH `abs d < d * &2 <=> &0 < d`] THEN DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN REWRITE_TAC[dist] THEN REWRITE_TAC[VECTOR_ARITH `x - (z + k % (z - x)) = (&1 + k) % (x - z)`] THEN REWRITE_TAC[REAL_NOT_LE; NORM_MUL] THEN GEN_REWRITE_TAC LAND_CONV [GSYM REAL_MUL_LID] THEN ONCE_REWRITE_TAC[NORM_SUB] THEN ASM_SIMP_TAC[REAL_LT_RMUL_EQ; GSYM dist] THEN MATCH_MP_TAC(REAL_ARITH `&0 < x ==> &1 < abs(&1 + x)`) THEN ONCE_REWRITE_TAC[DIST_SYM] THEN ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH]]);;
let FRONTIER_BALL = 
prove (`!a e. &0 < e ==> frontier(ball(a,e)) = sphere(a,e)`,
SIMP_TAC[frontier; sphere; CLOSURE_BALL; INTERIOR_OPEN; OPEN_BALL; REAL_LT_IMP_LE] THEN REWRITE_TAC[EXTENSION; IN_DIFF; IN_ELIM_THM; IN_BALL; IN_CBALL] THEN REAL_ARITH_TAC);;
let FRONTIER_CBALL = 
prove (`!a e. frontier(cball(a,e)) = sphere(a,e)`,
SIMP_TAC[frontier; sphere; INTERIOR_CBALL; CLOSED_CBALL; CLOSURE_CLOSED; REAL_LT_IMP_LE] THEN REWRITE_TAC[EXTENSION; IN_DIFF; IN_ELIM_THM; IN_BALL; IN_CBALL] THEN REAL_ARITH_TAC);;
let CBALL_EQ_EMPTY = 
prove (`!x e. (cball(x,e) = {}) <=> e < &0`,
let CBALL_EMPTY = 
prove (`!x e. e < &0 ==> cball(x,e) = {}`,
REWRITE_TAC[CBALL_EQ_EMPTY]);;
let CBALL_EQ_SING = 
prove (`!x:real^N e. (cball(x,e) = {x}) <=> e = &0`,
REPEAT GEN_TAC THEN REWRITE_TAC[EXTENSION; IN_CBALL; IN_SING] THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[DIST_LE_0]] THEN DISCH_THEN(fun th -> MP_TAC(SPEC `x + (e / &2) % basis 1:real^N` th) THEN MP_TAC(SPEC `x:real^N` th)) THEN REWRITE_TAC[dist; VECTOR_ARITH `x - (x + e):real^N = --e`; VECTOR_ARITH `x + e = x <=> e:real^N = vec 0`] THEN REWRITE_TAC[NORM_NEG; NORM_MUL; VECTOR_MUL_EQ_0; NORM_0; VECTOR_SUB_REFL] THEN SIMP_TAC[NORM_BASIS; BASIS_NONZERO; LE_REFL; DIMINDEX_GE_1] THEN REAL_ARITH_TAC);;
let CBALL_SING = 
prove (`!x e. e = &0 ==> cball(x,e) = {x}`,
REWRITE_TAC[CBALL_EQ_SING]);;
let SPHERE_SING = 
prove (`!x e. e = &0 ==> sphere(x,e) = {x}`,
SIMP_TAC[sphere; DIST_EQ_0; SING_GSPEC]);;
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. *) (* ------------------------------------------------------------------------- *)
let EVENTUALLY_WITHIN_INTERIOR = 
prove (`!p s x. x IN interior s ==> (eventually p (at x within s) <=> eventually p (at x))`,
REWRITE_TAC[EVENTUALLY_WITHIN; EVENTUALLY_AT; IN_INTERIOR] THEN REPEAT GEN_TAC THEN SIMP_TAC[SUBSET; IN_BALL; LEFT_IMP_FORALL_THM] THEN DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN EQ_TAC THEN DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN EXISTS_TAC `min (d:real) e` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN ASM_MESON_TAC[DIST_SYM]);;
let LIM_WITHIN_INTERIOR = 
prove (`!f l s x. x IN interior s ==> ((f --> l) (at x within s) <=> (f --> l) (at x))`,
SIMP_TAC[tendsto; EVENTUALLY_WITHIN_INTERIOR]);;
let NETLIMIT_WITHIN_INTERIOR = 
prove (`!s x:real^N. x IN interior s ==> netlimit(at x within s) = x`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC NETLIMIT_WITHIN THEN REWRITE_TAC[TRIVIAL_LIMIT_WITHIN] THEN FIRST_ASSUM(MP_TAC o MATCH_MP(REWRITE_RULE[OPEN_CONTAINS_BALL] (SPEC_ALL OPEN_INTERIOR))) THEN ASM_MESON_TAC[LIMPT_SUBSET; LIMPT_BALL; CENTRE_IN_CBALL; REAL_LT_IMP_LE; SUBSET_TRANS; INTERIOR_SUBSET]);;
(* ------------------------------------------------------------------------- *) (* A non-singleton connected set is perfect (i.e. has no isolated points). *) (* ------------------------------------------------------------------------- *)
let CONNECTED_IMP_PERFECT = 
prove (`!s x:real^N. connected s /\ ~(?a. s = {a}) /\ x IN s ==> x limit_point_of s`,
REPEAT STRIP_TAC THEN REWRITE_TAC[limit_point_of] THEN X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) 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 FIRST_X_ASSUM(MP_TAC o SPEC `{x:real^N}` o GEN_REWRITE_RULE I [CONNECTED_CLOPEN]) THEN REWRITE_TAC[NOT_IMP] THEN REPEAT CONJ_TAC THENL [REWRITE_TAC[OPEN_IN_OPEN] THEN EXISTS_TAC `t:real^N->bool` THEN ASM SET_TAC[]; REWRITE_TAC[CLOSED_IN_CLOSED] THEN EXISTS_TAC `cball(x:real^N,e)` THEN REWRITE_TAC[CLOSED_CBALL] THEN REWRITE_TAC[EXTENSION; IN_INTER; IN_SING] THEN ASM_MESON_TAC[CENTRE_IN_CBALL; SUBSET; REAL_LT_IMP_LE]; ASM SET_TAC[]]);;
(* ------------------------------------------------------------------------- *) (* Boundedness. *) (* ------------------------------------------------------------------------- *)
let bounded = new_definition
  `bounded s <=> ?a. !x:real^N. x IN s ==> norm(x) <= a`;;
let BOUNDED_EMPTY = 
prove (`bounded {}`,
REWRITE_TAC[bounded; NOT_IN_EMPTY]);;
let BOUNDED_SUBSET = 
prove (`!s t. bounded t /\ s SUBSET t ==> bounded s`,
MESON_TAC[bounded; SUBSET]);;
let BOUNDED_INTERIOR = 
prove (`!s:real^N->bool. bounded s ==> bounded(interior s)`,
let BOUNDED_CLOSURE = 
prove (`!s:real^N->bool. bounded s ==> bounded(closure s)`,
REWRITE_TAC[bounded; CLOSURE_SEQUENTIAL] THEN GEN_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN MESON_TAC[REWRITE_RULE[eventually] LIM_NORM_UBOUND; TRIVIAL_LIMIT_SEQUENTIALLY; trivial_limit]);;
let BOUNDED_CLOSURE_EQ = 
prove (`!s:real^N->bool. bounded(closure s) <=> bounded s`,
GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[BOUNDED_CLOSURE] THEN MESON_TAC[BOUNDED_SUBSET; CLOSURE_SUBSET]);;
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 BOUNDED_BALL = 
prove (`!x e. bounded(ball(x,e))`,
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_UNION = 
prove (`!s t. bounded (s UNION t) <=> bounded s /\ bounded t`,
REWRITE_TAC[bounded; IN_UNION] THEN MESON_TAC[REAL_LE_MAX]);;
let BOUNDED_UNIONS = 
prove (`!f. FINITE f /\ (!s. s IN f ==> bounded s) ==> bounded(UNIONS f)`,
REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[UNIONS_0; BOUNDED_EMPTY; IN_INSERT; UNIONS_INSERT] THEN MESON_TAC[BOUNDED_UNION]);;
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))`]);;
let BOUNDED_INTER = 
prove (`!s t. bounded s \/ bounded t ==> bounded (s INTER t)`,
let BOUNDED_DIFF = 
prove (`!s t. bounded s ==> bounded (s DIFF t)`,
MESON_TAC[BOUNDED_SUBSET; SUBSET_DIFF]);;
let BOUNDED_INSERT = 
prove (`!x s. bounded(x INSERT s) <=> bounded s`,
ONCE_REWRITE_TAC[SET_RULE `x INSERT s = {x} UNION s`] THEN SIMP_TAC[BOUNDED_UNION; FINITE_IMP_BOUNDED; FINITE_RULES]);;
let BOUNDED_SING = 
prove (`!a. bounded {a}`,
REWRITE_TAC[BOUNDED_INSERT; BOUNDED_EMPTY]);;
let BOUNDED_INTERS = 
prove (`!f:(real^N->bool)->bool. (?s:real^N->bool. s IN f /\ bounded s) ==> bounded(INTERS f)`,
REWRITE_TAC[LEFT_IMP_EXISTS_THM; IMP_CONJ] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] BOUNDED_SUBSET) THEN ASM SET_TAC[]);;
let NOT_BOUNDED_UNIV = 
prove (`~(bounded (:real^N))`,
REWRITE_TAC[BOUNDED_POS; NOT_FORALL_THM; NOT_EXISTS_THM; IN_UNIV; DE_MORGAN_THM; REAL_NOT_LE] THEN X_GEN_TAC `B:real` THEN ASM_CASES_TAC `&0 < B` THEN ASM_REWRITE_TAC[] THEN MP_TAC(SPEC `B + &1` VECTOR_CHOOSE_SIZE) THEN ASM_SIMP_TAC[REAL_ARITH `&0 < B ==> &0 <= B + &1`] THEN MATCH_MP_TAC MONO_EXISTS THEN REAL_ARITH_TAC);;
let COBOUNDED_IMP_UNBOUNDED = 
prove (`!s. bounded((:real^N) DIFF s) ==> ~bounded s`,
GEN_TAC THEN REWRITE_TAC[TAUT `a ==> ~b <=> ~(a /\ b)`] THEN REWRITE_TAC[GSYM BOUNDED_UNION; SET_RULE `UNIV DIFF s UNION s = UNIV`] THEN REWRITE_TAC[NOT_BOUNDED_UNIV]);;
let BOUNDED_LINEAR_IMAGE = 
prove (`!f:real^M->real^N s. bounded s /\ linear f ==> bounded(IMAGE f s)`,
REPEAT GEN_TAC THEN REWRITE_TAC[BOUNDED_POS] THEN DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `B1:real`) MP_TAC) THEN DISCH_THEN(X_CHOOSE_TAC `B2:real` o MATCH_MP LINEAR_BOUNDED_POS) THEN EXISTS_TAC `B2 * B1` THEN ASM_SIMP_TAC[REAL_LT_MUL; FORALL_IN_IMAGE] THEN X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `B2 * norm(x:real^M)` THEN ASM_SIMP_TAC[REAL_LE_LMUL_EQ]);;
let BOUNDED_LINEAR_IMAGE_EQ = 
prove (`!f s. linear f /\ (!x y. f x = f y ==> x = y) ==> (bounded (IMAGE f s) <=> bounded s)`,
MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE BOUNDED_LINEAR_IMAGE));;
add_linear_invariants [BOUNDED_LINEAR_IMAGE_EQ];;
let BOUNDED_SCALING = 
prove (`!c s. bounded s ==> bounded (IMAGE (\x. c % x) s)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC BOUNDED_LINEAR_IMAGE THEN ASM_SIMP_TAC[LINEAR_COMPOSE_CMUL; LINEAR_ID]);;
let BOUNDED_NEGATIONS = 
prove (`!s. bounded s ==> bounded (IMAGE (--) s)`,
GEN_TAC THEN DISCH_THEN(MP_TAC o SPEC `-- &1` o MATCH_MP BOUNDED_SCALING) THEN REWRITE_TAC[bounded; IN_IMAGE; VECTOR_MUL_LNEG; VECTOR_MUL_LID]);;
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);;
let BOUNDED_TRANSLATION_EQ = 
prove (`!a s. bounded (IMAGE (\x:real^N. a + x) s) <=> bounded s`,
REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[BOUNDED_TRANSLATION] THEN DISCH_THEN(MP_TAC o SPEC `--a:real^N` o MATCH_MP BOUNDED_TRANSLATION) THEN REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID; VECTOR_ARITH `--a + a + x:real^N = x`]);;
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_SUMS_IMAGE = 
prove (`!f g t. bounded {f x | x IN t} /\ bounded {g x | x IN t} ==> bounded {f x + g x | x IN t}`,
REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP BOUNDED_SUMS) THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] BOUNDED_SUBSET) THEN SET_TAC[]);;
let BOUNDED_SUMS_IMAGES = 
prove (`!f:A->B->real^N t s. FINITE s /\ (!a. a IN s ==> bounded {f x a | x IN t}) ==> bounded { vsum s (f x) | x IN t}`,
GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[VSUM_CLAUSES] THEN CONJ_TAC THENL [DISCH_THEN(K ALL_TAC) THEN MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `{vec 0:real^N}` THEN SIMP_TAC[FINITE_IMP_BOUNDED; FINITE_RULES] THEN SET_TAC[]; ALL_TAC] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC BOUNDED_SUMS_IMAGE THEN ASM_SIMP_TAC[IN_INSERT]);;
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);;
let BOUNDED_SUBSET_CBALL = 
prove (`!s x:real^N. bounded(s) ==> ?r. &0 < r /\ s SUBSET cball(x,r)`,
let UNBOUNDED_INTER_COBOUNDED = 
prove (`!s t. ~bounded s /\ bounded((:real^N) DIFF t) ==> ~(s INTER t = {})`,
REWRITE_TAC[SET_RULE `s INTER t = {} <=> s SUBSET (:real^N) DIFF t`] THEN MESON_TAC[BOUNDED_SUBSET]);;
let COBOUNDED_INTER_UNBOUNDED = 
prove (`!s t. bounded((:real^N) DIFF s) /\ ~bounded t ==> ~(s INTER t = {})`,
REWRITE_TAC[SET_RULE `s INTER t = {} <=> t SUBSET (:real^N) DIFF s`] THEN MESON_TAC[BOUNDED_SUBSET]);;
let SUBSPACE_BOUNDED_EQ_TRIVIAL = 
prove (`!s:real^N->bool. subspace s ==> (bounded s <=> s = {vec 0})`,
REPEAT STRIP_TAC THEN EQ_TAC THEN SIMP_TAC[BOUNDED_SING] THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE `~(s = {a}) ==> a IN s ==> ?b. b IN s /\ ~(b = a)`)) THEN ASM_SIMP_TAC[SUBSPACE_0] THEN DISCH_THEN(X_CHOOSE_THEN `v:real^N` STRIP_ASSUME_TAC) THEN REWRITE_TAC[bounded; NOT_EXISTS_THM] THEN X_GEN_TAC `B:real` THEN DISCH_THEN(MP_TAC o SPEC `(B + &1) / norm v % v:real^N`) THEN ASM_SIMP_TAC[SUBSPACE_MUL; NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0] THEN REAL_ARITH_TAC);;
let BOUNDED_COMPONENTWISE = 
prove (`!s:real^N->bool. bounded s <=> !i. 1 <= i /\ i <= dimindex(:N) ==> bounded (IMAGE (\x. lift(x$i)) s)`,
GEN_TAC THEN REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE; NORM_LIFT] THEN EQ_TAC THENL [ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LE_TRANS]; ALL_TAC] THEN GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN SIMP_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `b:num->real` THEN DISCH_TAC THEN EXISTS_TAC `sum(1..dimindex(:N)) b` THEN CONJ_TAC THENL [MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `sum(1..dimindex(:N)) (\i. &0)` THEN SIMP_TAC[SUM_POS_LE_NUMSEG; REAL_POS] THEN MATCH_MP_TAC SUM_LT_ALL THEN ASM_SIMP_TAC[IN_NUMSEG; FINITE_NUMSEG; NUMSEG_EMPTY] THEN REWRITE_TAC[NOT_LT; DIMINDEX_GE_1]; REPEAT STRIP_TAC THEN W(MP_TAC o PART_MATCH lhand NORM_LE_L1 o lhand o snd) THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN MATCH_MP_TAC SUM_LE THEN ASM_SIMP_TAC[IN_NUMSEG; FINITE_NUMSEG]]);;
(* ------------------------------------------------------------------------- *) (* Some theorems on sups and infs using the notion "bounded". *) (* ------------------------------------------------------------------------- *)
let BOUNDED_LIFT = 
prove (`!s. bounded(IMAGE lift s) <=> ?a. !x. x IN s ==> abs(x) <= a`,
REWRITE_TAC[bounded; FORALL_LIFT; NORM_LIFT; LIFT_IN_IMAGE_LIFT]);;
let BOUNDED_HAS_SUP = 
prove (`!s. bounded(IMAGE lift s) /\ ~(s = {}) ==> (!x. x IN s ==> x <= sup s) /\ (!b. (!x. x IN s ==> x <= b) ==> sup s <= b)`,
REWRITE_TAC[BOUNDED_LIFT; IMAGE_EQ_EMPTY] THEN MESON_TAC[SUP; REAL_ARITH `abs(x) <= a ==> x <= a`]);;
let SUP_INSERT = 
prove (`!x s. bounded (IMAGE lift s) ==> sup(x INSERT s) = if s = {} then x else max x (sup s)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_SUP_UNIQUE THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_SING] THENL [MESON_TAC[REAL_LE_REFL]; ALL_TAC] THEN REWRITE_TAC[REAL_LE_MAX; REAL_LT_MAX; IN_INSERT] THEN MP_TAC(ISPEC `s:real->bool` BOUNDED_HAS_SUP) THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN ASM_MESON_TAC[REAL_LE_REFL; REAL_NOT_LT]);;
let BOUNDED_HAS_INF = 
prove (`!s. bounded(IMAGE lift s) /\ ~(s = {}) ==> (!x. x IN s ==> inf s <= x) /\ (!b. (!x. x IN s ==> b <= x) ==> b <= inf s)`,
REWRITE_TAC[BOUNDED_LIFT; IMAGE_EQ_EMPTY] THEN MESON_TAC[INF; REAL_ARITH `abs(x) <= a ==> --a <= x`]);;
let INF_INSERT = 
prove (`!x s. bounded (IMAGE lift s) ==> inf(x INSERT s) = if s = {} then x else min x (inf s)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INF_UNIQUE THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_SING] THENL [MESON_TAC[REAL_LE_REFL]; ALL_TAC] THEN REWRITE_TAC[REAL_MIN_LE; REAL_MIN_LT; IN_INSERT] THEN MP_TAC(ISPEC `s:real->bool` BOUNDED_HAS_INF) THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN ASM_MESON_TAC[REAL_LE_REFL; REAL_NOT_LT]);;
(* ------------------------------------------------------------------------- *) (* 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 lemma = prove
   (`(!a':real^N r r'.
       cball(a,r) SUBSET cball(a',r') <=> dist(a,a') + r <= r' \/ r < &0) /\
     (!a':real^N r r'.
       cball(a,r) SUBSET ball(a',r') <=> dist(a,a') + r < r' \/ r < &0)`,
    CONJ_TAC THEN
    (GEOM_ORIGIN_TAC `a':real^N` THEN
    REPEAT GEN_TAC THEN REWRITE_TAC[SUBSET; IN_CBALL; IN_BALL] THEN
    EQ_TAC THENL [REWRITE_TAC[DIST_0]; NORM_ARITH_TAC] THEN
    DISJ_CASES_TAC(REAL_ARITH `r < &0 \/ &0 <= r`) THEN
    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN DISJ1_TAC THEN
    ASM_CASES_TAC `a:real^N = vec 0` THENL
     [FIRST_X_ASSUM(MP_TAC o SPEC `r % basis 1:real^N`) THEN
      ASM_SIMP_TAC[DIST_0; NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL];
      FIRST_X_ASSUM(MP_TAC o SPEC `(&1 + r / norm(a)) % a:real^N`) THEN
      SIMP_TAC[dist; VECTOR_ARITH `a - (&1 + x) % a:real^N = --(x % a)`] THEN
      ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; NORM_NEG; REAL_POS;
                   REAL_LE_DIV; NORM_POS_LE; REAL_ADD_RDISTRIB; REAL_DIV_RMUL;
               NORM_EQ_0; REAL_ARITH `&0 <= x ==> abs(&1 + x) = &1 + x`]] THEN
    UNDISCH_TAC `&0 <= r` THEN NORM_ARITH_TAC))
  and tac = DISCH_THEN(MP_TAC o MATCH_MP SUBSET_CLOSURE) THEN
            ASM_SIMP_TAC[CLOSED_CBALL; CLOSURE_CLOSED; CLOSURE_BALL] in
  REWRITE_TAC[AND_FORALL_THM] THEN GEOM_ORIGIN_TAC `a':real^N` THEN
  REPEAT STRIP_TAC THEN
  (EQ_TAC THENL
    [ALL_TAC; REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL] THEN NORM_ARITH_TAC]) THEN
  MATCH_MP_TAC(SET_RULE
   `(s = {} <=> q) /\ (s SUBSET t /\ ~(s = {}) /\ ~(t = {}) ==> p)
    ==> s SUBSET t ==> p \/ q`) THEN
  REWRITE_TAC[BALL_EQ_EMPTY; CBALL_EQ_EMPTY; REAL_NOT_LE; REAL_NOT_LT] THEN
  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THENL
   [tac; tac; ALL_TAC; ALL_TAC] THEN REWRITE_TAC[lemma] THEN
  REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC);;
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))`,
REPEAT STRIP_TAC THEN GEOM_ORIGIN_TAC `a:real^N` THEN GEOM_BASIS_MULTIPLE_TAC 1 `b:real^N` THEN REPEAT STRIP_TAC THEN REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_INTER; IN_CBALL; IN_BALL] THEN (EQ_TAC THENL [ALL_TAC; SPEC_TAC(`b % basis 1:real^N`,`v:real^N`) THEN CONV_TAC NORM_ARITH]) THEN DISCH_THEN(MP_TAC o GEN `c:real` o SPEC `c % basis 1:real^N`) THEN SIMP_TAC[NORM_MUL; NORM_BASIS; LE_REFL; DIMINDEX_GE_1; dist; NORM_NEG; VECTOR_SUB_LZERO; GSYM VECTOR_SUB_RDISTRIB; REAL_MUL_RID] THEN ASM_REWRITE_TAC[real_abs] THEN REWRITE_TAC[GSYM real_abs] THEN DISCH_THEN(fun th -> MP_TAC(SPEC `min b r:real` th) THEN MP_TAC(SPEC `max (&0) (b - s:real)` th) THEN MP_TAC(SPEC `(r + (b - s)) / &2` th)) THEN ASM_REAL_ARITH_TAC);;
(* ------------------------------------------------------------------------- *) (* Every closed set is a G_Delta. *) (* ------------------------------------------------------------------------- *)
let CLOSED_AS_GDELTA = 
prove (`!s:real^N->bool. closed s ==> ?g. COUNTABLE g /\ (!u. u IN g ==> open u) /\ INTERS g = s`,
REPEAT STRIP_TAC THEN EXISTS_TAC `{ UNIONS { ball(x:real^N,inv(&n + &1)) | x IN s} | n IN (:num)}` THEN SIMP_TAC[SIMPLE_IMAGE; COUNTABLE_IMAGE; NUM_COUNTABLE] THEN SIMP_TAC[FORALL_IN_IMAGE; OPEN_UNIONS; OPEN_BALL] THEN MATCH_MP_TAC(SET_RULE `closure s = s /\ s SUBSET t /\ t SUBSET closure s ==> t = s`) THEN ASM_REWRITE_TAC[CLOSURE_EQ] THEN CONJ_TAC THENL [REWRITE_TAC[SUBSET_INTERS; FORALL_IN_IMAGE; IN_UNIV] THEN X_GEN_TAC `n:num` THEN REWRITE_TAC[UNIONS_IMAGE; SUBSET; IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[CENTRE_IN_BALL; REAL_LT_INV_EQ] THEN REAL_ARITH_TAC; REWRITE_TAC[SUBSET; CLOSURE_APPROACHABLE; INTERS_IMAGE; IN_UNIV] THEN X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_ELIM_THM; UNIONS_IMAGE] THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_ARCH_INV]) THEN DISCH_THEN(X_CHOOSE_THEN `n:num` STRIP_ASSUME_TAC) THEN FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN REWRITE_TAC[IN_BALL] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^N` THEN MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LT_TRANS) THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] REAL_LT_TRANS)) THEN MATCH_MP_TAC REAL_LT_INV2 THEN REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LT] THEN ASM_ARITH_TAC]);;
(* ------------------------------------------------------------------------- *) (* 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`,
REWRITE_TAC[LIM_SEQUENTIALLY; o_THM] THEN MESON_TAC[MONOTONE_BIGGER; LE_TRANS]);;
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`,
REPEAT STRIP_TAC THENL [ASM_MESON_TAC[CONVERGENT_BOUNDED_INCREASING]; ALL_TAC] THEN MP_TAC(SPEC `\n. --((s:num->real) n)` CONVERGENT_BOUNDED_INCREASING) THEN ASM_REWRITE_TAC[REAL_LE_NEG2; REAL_ABS_NEG] THEN ASM_MESON_TAC[REAL_ARITH `abs(x - --l) = abs(--x - l)`]);;
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`,
REPEAT GEN_TAC THEN DISCH_TAC THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN MP_TAC(SPEC `s:num->real` MONOTONE_SUBSEQUENCE) THEN MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN DISCH_TAC THEN ASM_SIMP_TAC[] THEN MATCH_MP_TAC CONVERGENT_BOUNDED_MONOTONE THEN ASM_MESON_TAC[]);;
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`]);;
let BOUNDED_CLOSED_IMP_COMPACT = 
prove (`!s:real^N->bool. bounded s /\ closed s ==> compact s`,
REPEAT STRIP_TAC THEN REWRITE_TAC[compact] THEN X_GEN_TAC `x:num->real^N` THEN DISCH_TAC THEN MP_TAC(ISPEC `s:real^N->bool` COMPACT_LEMMA) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `dimindex(:N)`) THEN REWRITE_TAC[LE_REFL] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `l:real^N` THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `r:num->num` THEN ASM_SIMP_TAC[] THEN STRIP_TAC THEN MATCH_MP_TAC(TAUT `(b ==> a) /\ b ==> a /\ b`) THEN REPEAT STRIP_TAC THENL [FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[CLOSED_SEQUENTIAL_LIMITS]) THEN EXISTS_TAC `(x:num->real^N) o (r:num->num)` THEN ASM_REWRITE_TAC[o_THM]; ALL_TAC] THEN REWRITE_TAC[LIM_SEQUENTIALLY] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / &2 / &(dimindex(:N))`) THEN ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; DIMINDEX_NONZERO; REAL_HALF; ARITH_RULE `0 < n <=> ~(n = 0)`] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN REWRITE_TAC[dist] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC(MATCH_MP (REAL_ARITH `a <= b ==> b < e ==> a < e`) (SPEC_ALL NORM_LE_L1)) THEN MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `sum (1..dimindex(:N)) (\k. e / &2 / &(dimindex(:N)))` THEN CONJ_TAC THENL [MATCH_MP_TAC SUM_LE_NUMSEG THEN SIMP_TAC[o_THM; LAMBDA_BETA; vector_sub] THEN ASM_MESON_TAC[REAL_LT_IMP_LE; LE_TRANS]; ASM_SIMP_TAC[SUM_CONST_NUMSEG; ADD_SUB; REAL_DIV_LMUL; REAL_OF_NUM_EQ; DIMINDEX_NONZERO; REAL_LE_REFL; REAL_LT_LDIV_EQ; ARITH; REAL_OF_NUM_LT; REAL_ARITH `x < x * &2 <=> &0 < x`]]);;
(* ------------------------------------------------------------------------- *) (* Completeness. *) (* ------------------------------------------------------------------------- *)
let cauchy = new_definition
  `cauchy (s:num->real^N) <=>
     !e. &0 < e ==> ?N. !m n. m >= N /\ n >= N ==> dist(s m,s n) < e`;;
let complete = new_definition
  `complete s <=>
     !f:num->real^N. (!n. f n IN s) /\ cauchy f
                      ==> ?l. l IN s /\ (f --> l) sequentially`;;
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 CONVERGENT_IMP_CAUCHY = 
prove (`!s l. (s --> l) sequentially ==> cauchy s`,
REWRITE_TAC[LIM_SEQUENTIALLY; cauchy] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN ASM_MESON_TAC[GE; LE_REFL; DIST_TRIANGLE_HALF_L]);;
let CAUCHY_IMP_BOUNDED = 
prove (`!s:num->real^N. cauchy s ==> bounded {y | ?n. y = s n}`,
REWRITE_TAC[cauchy; bounded; IN_ELIM_THM] THEN GEN_TAC THEN DISCH_THEN(MP_TAC o SPEC `&1`) THEN REWRITE_TAC[REAL_LT_01] THEN DISCH_THEN(X_CHOOSE_THEN `N:num` (MP_TAC o SPEC `N:num`)) THEN REWRITE_TAC[GE_REFL] THEN DISCH_TAC THEN SUBGOAL_THEN `!n:num. N <= n ==> norm(s n :real^N) <= norm(s N) + &1` ASSUME_TAC THENL [ASM_MESON_TAC[GE; dist; DIST_SYM; NORM_TRIANGLE_SUB; REAL_ARITH `a <= b + c /\ c < &1 ==> a <= b + &1`]; MP_TAC(ISPECL [`\n:num. norm(s n :real^N)`; `0..N`] UPPER_BOUND_FINITE_SET_REAL) THEN SIMP_TAC[FINITE_NUMSEG; IN_NUMSEG; LE_0; LEFT_IMP_EXISTS_THM] THEN ASM_MESON_TAC[LE_CASES; REAL_ARITH `x <= a \/ x <= b ==> x <= abs a + abs b`]]);;
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]);;
let COMPLETE_UNIV = 
prove (`complete(:real^N)`,
REWRITE_TAC[complete; IN_UNIV] THEN X_GEN_TAC `x:num->real^N` THEN DISCH_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP CAUCHY_IMP_BOUNDED) THEN DISCH_THEN(ASSUME_TAC o MATCH_MP BOUNDED_CLOSURE) THEN MP_TAC(ISPEC `closure {y:real^N | ?n:num. y = x n}` COMPACT_IMP_COMPLETE) THEN ASM_SIMP_TAC[BOUNDED_CLOSED_IMP_COMPACT; CLOSED_CLOSURE; complete] THEN DISCH_THEN(MP_TAC o SPEC `x:num->real^N`) THEN ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN ASM_REWRITE_TAC[closure; IN_ELIM_THM; IN_UNION] THEN MESON_TAC[]);;
let COMPLETE_EQ_CLOSED = 
prove (`!s:real^N->bool. complete s <=> closed s`,
GEN_TAC THEN EQ_TAC THENL [REWRITE_TAC[complete; CLOSED_LIMPT; LIMPT_SEQUENTIAL] THEN REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN GEN_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN MATCH_MP_TAC MONO_FORALL THEN MESON_TAC[CONVERGENT_IMP_CAUCHY; IN_DELETE; LIM_UNIQUE; TRIVIAL_LIMIT_SEQUENTIALLY]; REWRITE_TAC[complete; CLOSED_SEQUENTIAL_LIMITS] THEN DISCH_TAC THEN X_GEN_TAC `f:num->real^N` THEN STRIP_TAC THEN MP_TAC(REWRITE_RULE[complete] COMPLETE_UNIV) THEN DISCH_THEN(MP_TAC o SPEC `f:num->real^N`) THEN ASM_REWRITE_TAC[IN_UNIV] THEN ASM_MESON_TAC[]]);;
let CONVERGENT_EQ_CAUCHY = 
prove (`!s. (?l. (s --> l) sequentially) <=> cauchy s`,
GEN_TAC THEN EQ_TAC THENL [REWRITE_TAC[LEFT_IMP_EXISTS_THM; CONVERGENT_IMP_CAUCHY]; REWRITE_TAC[REWRITE_RULE[complete; IN_UNIV] COMPLETE_UNIV]]);;
let CONVERGENT_IMP_BOUNDED = 
prove (`!s l. (s --> l) sequentially ==> bounded (IMAGE s (:num))`,
REWRITE_TAC[LEFT_FORALL_IMP_THM; CONVERGENT_EQ_CAUCHY] THEN REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP CAUCHY_IMP_BOUNDED) THEN REWRITE_TAC[IMAGE; IN_UNIV]);;
(* ------------------------------------------------------------------------- *) (* 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]);;
let COMPACT_IMP_HEINE_BOREL = 
prove (`!s. compact (s:real^N->bool) ==> !f. (!t. t IN f ==> open t) /\ s SUBSET (UNIONS f) ==> ?f'. f' SUBSET f /\ FINITE f' /\ s SUBSET (UNIONS f')`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o SPEC `f:(real^N->bool)->bool` o MATCH_MP HEINE_BOREL_LEMMA) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `e:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN REWRITE_TAC[SKOLEM_THM; SUBSET; IN_BALL] THEN DISCH_THEN(X_CHOOSE_TAC `B:real^N->real^N->bool`) THEN FIRST_ASSUM(MP_TAC o SPEC `e:real` o MATCH_MP COMPACT_IMP_TOTALLY_BOUNDED) THEN ASM_REWRITE_TAC[UNIONS_IMAGE; SUBSET; IN_ELIM_THM] THEN REWRITE_TAC[IN_UNIONS; IN_BALL] THEN DISCH_THEN(X_CHOOSE_THEN `k:real^N->bool` STRIP_ASSUME_TAC) THEN EXISTS_TAC `IMAGE (B:real^N->real^N->bool) k` THEN ASM_SIMP_TAC[FINITE_IMAGE; SUBSET; IN_IMAGE; LEFT_IMP_EXISTS_THM] THEN ASM_MESON_TAC[IN_BALL]);;
(* ------------------------------------------------------------------------- *) (* Bolzano-Weierstrass property. *) (* ------------------------------------------------------------------------- *)
let HEINE_BOREL_IMP_BOLZANO_WEIERSTRASS = 
prove (`!s:real^N->bool. (!f. (!t. t IN f ==> open t) /\ s SUBSET (UNIONS f) ==> ?f'. f' SUBSET f /\ FINITE f' /\ s SUBSET (UNIONS f')) ==> !t. INFINITE t /\ t SUBSET s ==> ?x. x IN s /\ x limit_point_of t`,
REWRITE_TAC[RIGHT_IMP_FORALL_THM; limit_point_of] THEN REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[TAUT `a ==> b /\ c ==> d <=> c ==> ~d ==> a ==> ~b`] THEN REWRITE_TAC[NOT_FORALL_THM; NOT_EXISTS_THM; RIGHT_AND_FORALL_THM] THEN DISCH_TAC THEN REWRITE_TAC[SKOLEM_THM] THEN DISCH_THEN(X_CHOOSE_TAC `f:real^N->real^N->bool`) THEN DISCH_THEN(MP_TAC o SPEC `{t:real^N->bool | ?x:real^N. x IN s /\ (t = f x)}`) THEN REWRITE_TAC[INFINITE; SUBSET; IN_ELIM_THM; IN_UNIONS; NOT_IMP] THEN ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN DISCH_THEN(X_CHOOSE_THEN `g:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `{x:real^N | x IN t /\ (f(x):real^N->bool) IN g}` THEN CONJ_TAC THENL [MATCH_MP_TAC FINITE_IMAGE_INJ_GENERAL THEN ASM_MESON_TAC[SUBSET]; SIMP_TAC[SUBSET; IN_ELIM_THM] THEN X_GEN_TAC `u:real^N` THEN DISCH_TAC THEN SUBGOAL_THEN `(u:real^N) IN s` ASSUME_TAC THEN ASM_MESON_TAC[SUBSET]]);;
(* ------------------------------------------------------------------------- *) (* Complete the chain of compactness variants. *) (* ------------------------------------------------------------------------- *)
let BOLZANO_WEIERSTRASS_IMP_BOUNDED = 
prove (`!s:real^N->bool. (!t. INFINITE t /\ t SUBSET s ==> ?x. x limit_point_of t) ==> bounded s`,
GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN SIMP_TAC[compact; bounded] THEN REWRITE_TAC[NOT_FORALL_THM; NOT_EXISTS_THM; SKOLEM_THM; NOT_IMP] THEN REWRITE_TAC[REAL_NOT_LE] THEN DISCH_THEN(X_CHOOSE_TAC `beyond:real->real^N`) THEN (MP_TAC o prove_recursive_functions_exist num_RECURSION) `(f(0) = beyond(&0)) /\ (!n. f(SUC n) = beyond(norm(f n) + &1):real^N)` THEN DISCH_THEN(X_CHOOSE_THEN `x:num->real^N` STRIP_ASSUME_TAC) THEN EXISTS_TAC `IMAGE (x:num->real^N) UNIV` THEN SUBGOAL_THEN `!m n. m < n ==> norm((x:num->real^N) m) + &1 < norm(x n)` ASSUME_TAC THENL [GEN_TAC THEN INDUCT_TAC THEN ASM_REWRITE_TAC[LT] THEN ASM_MESON_TAC[REAL_LT_TRANS; REAL_ARITH `b < b + &1`]; ALL_TAC] THEN SUBGOAL_THEN `!m n. ~(m = n) ==> &1 < dist((x:num->real^N) m,x n)` ASSUME_TAC THENL [REPEAT GEN_TAC THEN REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (SPECL [`m:num`; `n:num`] LT_CASES) THEN ASM_MESON_TAC[dist; LT_CASES; NORM_TRIANGLE_SUB; NORM_SUB; REAL_ARITH `x + &1 < y /\ y <= x + d ==> &1 < d`]; ALL_TAC] THEN REPEAT CONJ_TAC THENL [ASM_MESON_TAC[INFINITE_IMAGE_INJ; num_INFINITE; DIST_REFL; REAL_ARITH `~(&1 < &0)`]; REWRITE_TAC[SUBSET; IN_IMAGE; IN_UNIV; LEFT_IMP_EXISTS_THM] THEN GEN_TAC THEN INDUCT_TAC THEN ASM_MESON_TAC[]; ALL_TAC] THEN X_GEN_TAC `l:real^N` THEN REWRITE_TAC[LIMPT_APPROACHABLE] THEN REWRITE_TAC[IN_IMAGE; IN_UNIV; LEFT_AND_EXISTS_THM] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[UNWIND_THM2] THEN STRIP_TAC THEN FIRST_ASSUM(MP_TAC o SPEC `&1 / &2`) THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN DISCH_THEN(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN FIRST_X_ASSUM(MP_TAC o SPEC `dist((x:num->real^N) k,l)`) THEN ASM_SIMP_TAC[DIST_POS_LT] THEN DISCH_THEN(X_CHOOSE_THEN `m:num` STRIP_ASSUME_TAC) THEN ASM_CASES_TAC `m:num = k` THEN ASM_MESON_TAC[DIST_TRIANGLE_HALF_L; REAL_LT_TRANS; REAL_LT_REFL]);;
let SEQUENCE_INFINITE_LEMMA = 
prove (`!f l. (!n. ~(f(n) = l)) /\ (f --> l) sequentially ==> INFINITE {y:real^N | ?n. y = f n}`,
REWRITE_TAC[INFINITE] THEN REPEAT STRIP_TAC THEN MP_TAC(ISPEC `IMAGE (\y:real^N. dist(y,l)) {y | ?n:num. y = f n}` INF_FINITE) THEN ASM_SIMP_TAC[GSYM MEMBER_NOT_EMPTY; IN_IMAGE; FINITE_IMAGE; IN_ELIM_THM] THEN ASM_MESON_TAC[LIM_SEQUENTIALLY; LE_REFL; REAL_NOT_LE; DIST_POS_LT]);;
let LIMPT_OF_SEQUENCE_SUBSEQUENCE = 
prove (`!f:num->real^N l. l limit_point_of (IMAGE f (:num)) ==> ?r. (!m n. m < n ==> r(m) < r(n)) /\ ((f o r) --> l) sequentially`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIMPT_APPROACHABLE]) THEN DISCH_THEN(MP_TAC o GEN `n:num` o SPEC `inf((inv(&n + &1)) INSERT IMAGE (\k. dist((f:num->real^N) k,l)) {k | k IN 0..n /\ ~(f k = l)})`) THEN SIMP_TAC[REAL_LT_INF_FINITE; FINITE_INSERT; NOT_INSERT_EMPTY; FINITE_RESTRICT; FINITE_NUMSEG; FINITE_IMAGE] THEN REWRITE_TAC[FORALL_IN_INSERT; EXISTS_IN_IMAGE; FORALL_IN_IMAGE; IN_UNIV] THEN REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`] THEN SIMP_TAC[FORALL_AND_THM; FORALL_IN_GSPEC; GSYM DIST_NZ; SKOLEM_THM] THEN DISCH_THEN(X_CHOOSE_THEN `nn:num->num` STRIP_ASSUME_TAC) THEN (MP_TAC o prove_recursive_functions_exist num_RECURSION) `r 0 = nn 0 /\ (!n. r (SUC n) = nn(r n))` THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `r:num->num` THEN STRIP_TAC THEN MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL [MATCH_MP_TAC TRANSITIVE_STEPWISE_LT THEN REWRITE_TAC[LT_TRANS] THEN X_GEN_TAC `n:num` THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MP_TAC o SPECL [`(r:num->num) n`; `(nn:num->num)(r(n:num))`]) THEN ASM_REWRITE_TAC[IN_NUMSEG; LE_0; REAL_LT_REFL] THEN ARITH_TAC; DISCH_THEN(ASSUME_TAC o MATCH_MP MONOTONE_BIGGER)] THEN REWRITE_TAC[LIM_SEQUENTIALLY] THEN X_GEN_TAC `e:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_ARCH_INV] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN STRIP_TAC THEN MATCH_MP_TAC num_INDUCTION THEN ASM_REWRITE_TAC[CONJUNCT1 LE] THEN X_GEN_TAC `n:num` THEN DISCH_THEN(K ALL_TAC) THEN DISCH_TAC THEN ASM_REWRITE_TAC[o_THM] THEN MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `inv(&((r:num->num) n) + &1)` THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&N)` THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_INV2 THEN ASM_SIMP_TAC[REAL_OF_NUM_LE; REAL_OF_NUM_LT; LE_1; REAL_OF_NUM_ADD] THEN MATCH_MP_TAC(ARITH_RULE `N <= SUC n /\ n <= r n ==> N <= r n + 1`) THEN ASM_REWRITE_TAC[]);;
let SEQUENCE_UNIQUE_LIMPT = 
prove (`!f l l':real^N. (f --> l) sequentially /\ l' limit_point_of {y | ?n. y = f n} ==> l' = l`,
REWRITE_TAC[SET_RULE `{y | ?n. y = f n} = IMAGE f (:num)`] THEN REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o MATCH_MP LIMPT_OF_SEQUENCE_SUBSEQUENCE) THEN DISCH_THEN(X_CHOOSE_THEN `r:num->num` STRIP_ASSUME_TAC) THEN MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN EXISTS_TAC `(f:num->real^N) o (r:num->num)` THEN ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; LIM_SUBSEQUENCE]);;
let BOLZANO_WEIERSTRASS_IMP_CLOSED = 
prove (`!s:real^N->bool. (!t. INFINITE t /\ t SUBSET s ==> ?x. x IN s /\ x limit_point_of t) ==> closed s`,
REPEAT STRIP_TAC THEN REWRITE_TAC[CLOSED_SEQUENTIAL_LIMITS] THEN MAP_EVERY X_GEN_TAC [`f:num->real^N`; `l:real^N`] THEN DISCH_TAC THEN MAP_EVERY (MP_TAC o ISPECL [`f:num->real^N`; `l:real^N`]) [SEQUENCE_UNIQUE_LIMPT; SEQUENCE_INFINITE_LEMMA] THEN MATCH_MP_TAC(TAUT `(~d ==> a /\ ~(b /\ c)) ==> (a ==> b) ==> c ==> d`) THEN DISCH_TAC THEN CONJ_TAC THENL [ASM_MESON_TAC[]; STRIP_TAC] THEN FIRST_X_ASSUM(MP_TAC o SPEC `{y:real^N | ?n:num. y = f n}`) THEN ASM_REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL [REWRITE_TAC[SUBSET; IN_ELIM_THM]; ABBREV_TAC `t = {y:real^N | ?n:num. y = f n}`] THEN ASM_MESON_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Hence express everything as an equivalence. *) (* ------------------------------------------------------------------------- *)
let COMPACT_EQ_HEINE_BOREL = 
prove (`!s:real^N->bool. compact s <=> !f. (!t. t IN f ==> open t) /\ s SUBSET (UNIONS f) ==> ?f'. f' SUBSET f /\ FINITE f' /\ s SUBSET (UNIONS f')`,
GEN_TAC THEN EQ_TAC THEN SIMP_TAC[COMPACT_IMP_HEINE_BOREL] THEN DISCH_THEN(MP_TAC o MATCH_MP HEINE_BOREL_IMP_BOLZANO_WEIERSTRASS) THEN DISCH_TAC THEN MATCH_MP_TAC BOUNDED_CLOSED_IMP_COMPACT THEN ASM_MESON_TAC[BOLZANO_WEIERSTRASS_IMP_BOUNDED; BOLZANO_WEIERSTRASS_IMP_CLOSED]);;
let COMPACT_EQ_BOLZANO_WEIERSTRASS = 
prove (`!s:real^N->bool. compact s <=> !t. INFINITE t /\ t SUBSET s ==> ?x. x IN s /\ x limit_point_of t`,
let COMPACT_EQ_BOUNDED_CLOSED = 
prove (`!s:real^N->bool. compact s <=> bounded s /\ closed s`,
let COMPACT_IMP_BOUNDED = 
prove (`!s. compact s ==> bounded s`,
let COMPACT_IMP_CLOSED = 
prove (`!s. compact s ==> closed s`,
let COMPACT_SEQUENCE_WITH_LIMIT = 
prove (`!f l:real^N. (f --> l) sequentially ==> compact (l INSERT IMAGE f (:num))`,
REPEAT STRIP_TAC THEN REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN REWRITE_TAC[BOUNDED_INSERT] THEN CONJ_TAC THENL [ASM_MESON_TAC[CONVERGENT_IMP_BOUNDED]; SIMP_TAC[CLOSED_LIMPT; LIMPT_INSERT; IN_INSERT] THEN REWRITE_TAC[IMAGE; IN_UNIV] THEN REPEAT STRIP_TAC THEN DISJ1_TAC THEN MATCH_MP_TAC SEQUENCE_UNIQUE_LIMPT THEN ASM_MESON_TAC[]]);;
let CLOSED_IN_COMPACT = 
prove (`!s t:real^N->bool. compact s /\ closed_in (subtopology euclidean s) t ==> compact t`,
let CLOSED_IN_COMPACT_EQ = 
prove (`!s t. compact s ==> (closed_in (subtopology euclidean s) t <=> compact t /\ t SUBSET s)`,
(* ------------------------------------------------------------------------- *) (* A version of Heine-Borel for subtopology. *) (* ------------------------------------------------------------------------- *)
let COMPACT_EQ_HEINE_BOREL_SUBTOPOLOGY = 
prove (`!s:real^N->bool. compact s <=> (!f. (!t. t IN f ==> open_in(subtopology euclidean s) t) /\ s SUBSET UNIONS f ==> ?f'. f' SUBSET f /\ FINITE f' /\ s SUBSET UNIONS f')`,
GEN_TAC THEN REWRITE_TAC[COMPACT_EQ_HEINE_BOREL] THEN EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `f:(real^N->bool)->bool` THENL [REWRITE_TAC[OPEN_IN_OPEN] THEN GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN REWRITE_TAC[SKOLEM_THM] THEN DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `m:(real^N->bool)->(real^N->bool)`) ASSUME_TAC) THEN FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (m:(real^N->bool)->(real^N->bool)) f`) THEN ASM_SIMP_TAC[FORALL_IN_IMAGE] THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN DISCH_THEN(X_CHOOSE_THEN `f':(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN EXISTS_TAC `IMAGE (\t:real^N->bool. s INTER t) f'` THEN ASM_SIMP_TAC[FINITE_IMAGE; UNIONS_IMAGE; SUBSET; FORALL_IN_IMAGE] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET_IMAGE]) THEN STRIP_TAC THEN ASM_REWRITE_TAC[FORALL_IN_IMAGE] THEN ASM_MESON_TAC[SUBSET]; DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `{s INTER t:real^N->bool | t IN f}`) THEN REWRITE_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; OPEN_IN_OPEN; UNIONS_IMAGE] THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN REWRITE_TAC[EXISTS_FINITE_SUBSET_IMAGE; UNIONS_IMAGE] THEN MATCH_MP_TAC MONO_EXISTS THEN SET_TAC[]]);;
(* ------------------------------------------------------------------------- *) (* More easy lemmas. *) (* ------------------------------------------------------------------------- *)
let COMPACT_CLOSURE = 
prove (`!s. compact(closure s) <=> bounded s`,
let BOLZANO_WEIERSTRASS_CONTRAPOS = 
prove (`!s t:real^N->bool. compact s /\ t SUBSET s /\ (!x. x IN s ==> ~(x limit_point_of t)) ==> FINITE t`,
REWRITE_TAC[COMPACT_EQ_BOLZANO_WEIERSTRASS; INFINITE] THEN MESON_TAC[]);;
let DISCRETE_BOUNDED_IMP_FINITE = 
prove (`!s:real^N->bool e. &0 < e /\ (!x y. x IN s /\ y IN s /\ norm(y - x) < e ==> y = x) /\ bounded s ==> FINITE s`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `compact(s:real^N->bool)` MP_TAC THENL [ASM_REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN ASM_MESON_TAC[DISCRETE_IMP_CLOSED]; DISCH_THEN(MP_TAC o MATCH_MP COMPACT_IMP_HEINE_BOREL)] THEN DISCH_THEN(MP_TAC o SPEC `IMAGE (\x:real^N. ball(x,e)) s`) THEN REWRITE_TAC[FORALL_IN_IMAGE; OPEN_BALL; UNIONS_IMAGE; IN_ELIM_THM] THEN ANTS_TAC THENL [REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN ASM_MESON_TAC[CENTRE_IN_BALL]; ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`]] THEN REWRITE_TAC[EXISTS_FINITE_SUBSET_IMAGE] THEN DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN SUBGOAL_THEN `s:real^N->bool = t` (fun th -> ASM_REWRITE_TAC[th]) THEN MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [UNIONS_IMAGE]) THEN DISCH_THEN(MP_TAC o SPEC `x:real^N` o GEN_REWRITE_RULE I [SUBSET]) THEN ASM_REWRITE_TAC[IN_ELIM_THM; IN_BALL; dist] THEN ASM_MESON_TAC[SUBSET]);;
let BOLZANO_WEIERSTRASS = 
prove (`!s:real^N->bool. bounded s /\ INFINITE s ==> ?x. x limit_point_of s`,
GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP NO_LIMIT_POINT_IMP_CLOSED) THEN STRIP_TAC THEN MP_TAC(ISPEC `s:real^N->bool` COMPACT_EQ_BOLZANO_WEIERSTRASS) THEN ASM_REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN DISCH_THEN(MP_TAC o SPEC `s:real^N->bool`) THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN ASM_MESON_TAC[]);;
let BOUNDED_EQ_BOLZANO_WEIERSTRASS = 
prove (`!s:real^N->bool. bounded s <=> !t. t SUBSET s /\ INFINITE t ==> ?x. x limit_point_of t`,
(* ------------------------------------------------------------------------- *) (* In particular, some common special cases. *) (* ------------------------------------------------------------------------- *)
let COMPACT_EMPTY = 
prove (`compact {}`,
REWRITE_TAC[compact; NOT_IN_EMPTY]);;
let COMPACT_UNION = 
prove (`!s t. compact s /\ compact t ==> compact (s UNION t)`,
let COMPACT_INTER = 
prove (`!s t. compact s /\ compact t ==> compact (s INTER t)`,
let COMPACT_INTER_CLOSED = 
prove (`!s t. compact s /\ closed t ==> compact (s INTER t)`,
let CLOSED_INTER_COMPACT = 
prove (`!s t. closed s /\ compact t ==> compact (s INTER t)`,
let COMPACT_INTERS = 
prove (`!f:(real^N->bool)->bool. (!s. s IN f ==> compact s) /\ ~(f = {}) ==> compact(INTERS f)`,
SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_INTERS] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC BOUNDED_INTERS THEN ASM SET_TAC[]);;
let FINITE_IMP_CLOSED = 
prove (`!s. FINITE s ==> closed s`,
let FINITE_IMP_CLOSED_IN = 
prove (`!s t. FINITE s /\ s SUBSET t ==> closed_in (subtopology euclidean t) s`,
let FINITE_IMP_COMPACT = 
prove (`!s. FINITE s ==> compact s`,
let COMPACT_SING = 
prove (`!a. compact {a}`,
let COMPACT_INSERT = 
prove (`!a s. compact s ==> compact(a INSERT s)`,
ONCE_REWRITE_TAC[SET_RULE `a INSERT s = {a} UNION s`] THEN SIMP_TAC[COMPACT_UNION; COMPACT_SING]);;
let CLOSED_SING = 
prove (`!a. closed {a}`,
let CLOSED_IN_SING = 
prove (`!u x:real^N. closed_in (subtopology euclidean u) {x} <=> x IN u`,
SIMP_TAC[CLOSED_SUBSET_EQ; CLOSED_SING] THEN SET_TAC[]);;
let CLOSURE_SING = 
prove (`!x:real^N. closure {x} = {x}`,
let CLOSED_INSERT = 
prove (`!a s. closed s ==> closed(a INSERT s)`,
ONCE_REWRITE_TAC[SET_RULE `a INSERT s = {a} UNION s`] THEN SIMP_TAC[CLOSED_UNION; CLOSED_SING]);;
let COMPACT_CBALL = 
prove (`!x e. compact(cball(x,e))`,
let COMPACT_FRONTIER_BOUNDED = 
prove (`!s. bounded s ==> compact(frontier s)`,
let COMPACT_FRONTIER = 
prove (`!s. compact s ==> compact (frontier s)`,
let BOUNDED_FRONTIER = 
prove (`!s:real^N->bool. bounded s ==> bounded(frontier s)`,
let FRONTIER_SUBSET_COMPACT = 
prove (`!s. compact s ==> frontier s SUBSET s`,
let OPEN_DELETE = 
prove (`!s x. open s ==> open(s DELETE x)`,
let lemma = prove(`s DELETE x = s DIFF {x}`,SET_TAC[]) in
  SIMP_TAC[lemma; OPEN_DIFF; CLOSED_SING]);;
let OPEN_IN_DELETE = 
prove (`!u s a:real^N. open_in (subtopology euclidean u) s ==> open_in (subtopology euclidean u) (s DELETE a)`,
REPEAT STRIP_TAC THEN ASM_CASES_TAC `(a:real^N) IN s` THENL [ONCE_REWRITE_TAC[SET_RULE `s DELETE a = s DIFF {a}`] THEN MATCH_MP_TAC OPEN_IN_DIFF THEN ASM_REWRITE_TAC[CLOSED_IN_SING] THEN FIRST_X_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN ASM SET_TAC[]; ASM_SIMP_TAC[SET_RULE `~(a IN s) ==> s DELETE a = s`]]);;
let CLOSED_INTERS_COMPACT = 
prove (`!s:real^N->bool. closed s <=> !e. compact(cball(vec 0,e) INTER s)`,
GEN_TAC THEN EQ_TAC THENL [SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_INTER; CLOSED_CBALL; BOUNDED_INTER; BOUNDED_CBALL]; ALL_TAC] THEN STRIP_TAC THEN REWRITE_TAC[CLOSED_LIMPT] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `norm(x:real^N) + &1`) THEN DISCH_THEN(MP_TAC o MATCH_MP COMPACT_IMP_CLOSED) THEN REWRITE_TAC[CLOSED_LIMPT] THEN DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN REWRITE_TAC[IN_INTER] THEN ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN POP_ASSUM MP_TAC THEN REWRITE_TAC[LIMPT_APPROACHABLE] THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `min e (&1 / &2)`) THEN ANTS_TAC THENL [ASM_REAL_ARITH_TAC; MATCH_MP_TAC MONO_EXISTS] THEN X_GEN_TAC `y:real^N` THEN SIMP_TAC[IN_INTER; IN_CBALL] THEN NORM_ARITH_TAC);;
let COMPACT_UNIONS = 
prove (`!s. FINITE s /\ (!t. t IN s ==> compact t) ==> compact(UNIONS s)`,
let COMPACT_DIFF = 
prove (`!s t. compact s /\ open t ==> compact(s DIFF t)`,
ONCE_REWRITE_TAC[SET_RULE `s DIFF t = s INTER (UNIV DIFF t)`] THEN SIMP_TAC[COMPACT_INTER_CLOSED; GSYM OPEN_CLOSED]);;
let COMPACT_SPHERE = 
prove (`!a:real^N r. compact(sphere(a,r))`,
REPEAT GEN_TAC THEN REWRITE_TAC[GSYM FRONTIER_CBALL] THEN MATCH_MP_TAC COMPACT_FRONTIER THEN REWRITE_TAC[COMPACT_CBALL]);;
let BOUNDED_SPHERE = 
prove (`!a:real^N r. bounded(sphere(a,r))`,
let CLOSED_SPHERE = 
prove (`!a r. closed(sphere(a,r))`,
let FRONTIER_SING = 
prove (`!a:real^N. frontier {a} = {a}`,
REWRITE_TAC[frontier; CLOSURE_SING; INTERIOR_SING; DIFF_EMPTY]);;
(* ------------------------------------------------------------------------- *) (* Finite intersection property. I could make it an equivalence in fact. *) (* ------------------------------------------------------------------------- *)
let COMPACT_IMP_FIP = 
prove (`!s:real^N->bool f. compact s /\ (!t. t IN f ==> closed t) /\ (!f'. FINITE f' /\ f' SUBSET f ==> ~(s INTER (INTERS f') = {})) ==> ~(s INTER (INTERS f) = {})`,
let lemma = prove(`(s = UNIV DIFF t) <=> (UNIV DIFF s = t)`,SET_TAC[]) in
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [COMPACT_EQ_HEINE_BOREL]) THEN
  DISCH_THEN(MP_TAC o SPEC `IMAGE (\t:real^N->bool. UNIV DIFF t) f`) THEN
  ASM_SIMP_TAC[FORALL_IN_IMAGE] THEN
  DISCH_THEN(fun th -> REPEAT STRIP_TAC THEN MP_TAC th) THEN
  ASM_SIMP_TAC[OPEN_DIFF; CLOSED_DIFF; OPEN_UNIV; CLOSED_UNIV; NOT_IMP] THEN
  CONJ_TAC THENL
   [UNDISCH_TAC `(s:real^N->bool) INTER INTERS f = {}` THEN
    ONCE_REWRITE_TAC[SUBSET; EXTENSION] THEN
    REWRITE_TAC[IN_UNIONS; EXISTS_IN_IMAGE] THEN SET_TAC[];
    DISCH_THEN(X_CHOOSE_THEN `g:(real^N->bool)->bool` MP_TAC) THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (\t:real^N->bool. UNIV DIFF t) g`) THEN
    ASM_CASES_TAC `FINITE(g:(real^N->bool)->bool)` THEN
    ASM_SIMP_TAC[FINITE_IMAGE] THEN ONCE_REWRITE_TAC[SUBSET; EXTENSION] THEN
    REWRITE_TAC[FORALL_IN_IMAGE; IN_INTER; IN_INTERS; IN_IMAGE; IN_DIFF;
                IN_UNIV; NOT_IN_EMPTY; lemma; UNWIND_THM1; IN_UNIONS] THEN
    SET_TAC[]]);;
let CLOSED_IMP_FIP = 
prove (`!s:real^N->bool f. closed s /\ (!t. t IN f ==> closed t) /\ (?t. t IN f /\ bounded t) /\ (!f'. FINITE f' /\ f' SUBSET f ==> ~(s INTER (INTERS f') = {})) ==> ~(s INTER (INTERS f) = {})`,
REPEAT GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC(SET_RULE `~((s INTER t) INTER u = {}) ==> ~(s INTER u = {})`) THEN MATCH_MP_TAC COMPACT_IMP_FIP THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_MESON_TAC[CLOSED_INTER_COMPACT; COMPACT_EQ_BOUNDED_CLOSED]; REWRITE_TAC[INTER_ASSOC] THEN ONCE_REWRITE_TAC[GSYM INTERS_INSERT]] THEN GEN_TAC THEN STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[FINITE_INSERT; INSERT_SUBSET]);;
let CLOSED_IMP_FIP_COMPACT = 
prove (`!s:real^N->bool f. closed s /\ (!t. t IN f ==> compact t) /\ (!f'. FINITE f' /\ f' SUBSET f ==> ~(s INTER (INTERS f') = {})) ==> ~(s INTER (INTERS f) = {})`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN ASM_SIMP_TAC[SUBSET_EMPTY; INTERS_0; INTER_UNIV] THENL [MESON_TAC[FINITE_EMPTY]; ALL_TAC] THEN STRIP_TAC THEN MATCH_MP_TAC CLOSED_IMP_FIP THEN ASM_MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; MEMBER_NOT_EMPTY]);;
let CLOSED_FIP = 
prove (`!f. (!t:real^N->bool. t IN f ==> closed t) /\ (?t. t IN f /\ bounded t) /\ (!f'. FINITE f' /\ f' SUBSET f ==> ~(INTERS f' = {})) ==> ~(INTERS f = {})`,
GEN_TAC THEN DISCH_TAC THEN ONCE_REWRITE_TAC[SET_RULE `s = {} <=> UNIV INTER s = {}`] THEN MATCH_MP_TAC CLOSED_IMP_FIP THEN ASM_REWRITE_TAC[CLOSED_UNIV; INTER_UNIV]);;
let COMPACT_FIP = 
prove (`!f. (!t:real^N->bool. t IN f ==> compact t) /\ (!f'. FINITE f' /\ f' SUBSET f ==> ~(INTERS f' = {})) ==> ~(INTERS f = {})`,
GEN_TAC THEN DISCH_TAC THEN ONCE_REWRITE_TAC[SET_RULE `s = {} <=> UNIV INTER s = {}`] THEN MATCH_MP_TAC CLOSED_IMP_FIP_COMPACT THEN ASM_REWRITE_TAC[CLOSED_UNIV; INTER_UNIV]);;
(* ------------------------------------------------------------------------- *) (* 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)`,
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 `?l:real^N. (a --> l) sequentially` MP_TAC THENL [ASM_MESON_TAC[cauchy; GE; SUBSET; LE_TRANS; LE_REFL; complete; COMPLETE_UNIV; IN_UNIV]; ASM_MESON_TAC[LIM_SEQUENTIALLY; CLOSED_APPROACHABLE; SUBSET; LE_REFL; LE_TRANS; LE_CASES]]);;
(* ------------------------------------------------------------------------- *) (* Strengthen it to the intersection actually being a singleton. *) (* ------------------------------------------------------------------------- *)
let DECREASING_CLOSED_NEST_SING = 
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. INTERS {t | ?n:num. t = s n} = {a}`,
GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP DECREASING_CLOSED_NEST) THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN REWRITE_TAC[EXTENSION; IN_INTERS; IN_SING; IN_ELIM_THM] THEN ASM_MESON_TAC[DIST_POS_LT; REAL_LT_REFL; SUBSET; LE_CASES]);;
(* ------------------------------------------------------------------------- *) (* 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. *) (* ------------------------------------------------------------------------- *)
let COMPACT_CHAIN = 
prove (`!f:(real^N->bool)->bool. (!s. s IN f ==> compact s /\ ~(s = {})) /\ (!s t. s IN f /\ t IN f ==> s SUBSET t \/ t SUBSET s) ==> ~(INTERS f = {})`,
GEN_TAC THEN REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN STRIP_TAC THEN ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THENL [ASM_REWRITE_TAC[INTERS_0] THEN SET_TAC[]; MATCH_MP_TAC BOUNDED_CLOSED_CHAIN THEN ASM SET_TAC[]]);;
let COMPACT_NEST = 
prove (`!s. (!n. compact(s n) /\ ~(s n = {})) /\ (!m n. m <= n ==> s n SUBSET s m) ==> ~(INTERS {s n | n IN (:num)} = {})`,
GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC COMPACT_CHAIN THEN ASM_SIMP_TAC[FORALL_IN_GSPEC; IN_UNIV; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC WLOG_LE THEN ASM_MESON_TAC[]);;
(* ------------------------------------------------------------------------- *) (* 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 = new_definition
  `f continuous net <=> (f --> f(netlimit net)) net`;;
let CONTINUOUS_TRIVIAL_LIMIT = 
prove (`!f net. trivial_limit net ==> f continuous net`,
SIMP_TAC[continuous; LIM]);;
let CONTINUOUS_WITHIN = 
prove (`!f x:real^M. f continuous (at x within s) <=> (f --> f(x)) (at x within s)`,
REPEAT GEN_TAC THEN REWRITE_TAC[continuous] THEN ASM_CASES_TAC `trivial_limit(at (x:real^M) within s)` THENL [ASM_REWRITE_TAC[LIM]; ASM_SIMP_TAC[NETLIMIT_WITHIN]]);;
let CONTINUOUS_AT = 
prove (`!f (x:real^N). f continuous (at x) <=> (f --> f(x)) (at x)`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN REWRITE_TAC[CONTINUOUS_WITHIN; IN_UNIV]);;
let CONTINUOUS_AT_WITHIN = 
prove (`!f:real^M->real^N x s. f continuous (at x) ==> f continuous (at x within s)`,
let CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL = 
prove (`!a s. closed s /\ ~(a IN s) ==> f continuous (at a within s)`,
ASM_SIMP_TAC[continuous; LIM; LIM_WITHIN_CLOSED_TRIVIAL]);;
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)`,
REWRITE_TAC[CONTINUOUS_WITHIN] THEN MESON_TAC[LIM_TRANSFORM_WITHIN; DIST_REFL]);;
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)`,
REWRITE_TAC[CONTINUOUS_AT] THEN MESON_TAC[LIM_TRANSFORM_AT; DIST_REFL]);;
let CONTINUOUS_TRANSFORM_WITHIN_OPEN = 
prove (`!f g:real^M->real^N s a. open s /\ a IN s /\ (!x. x IN s ==> f x = g x) /\ f continuous at a ==> g continuous at a`,
let CONTINUOUS_TRANSFORM_WITHIN_OPEN_IN = 
prove (`!f g:real^M->real^N s t a. open_in (subtopology euclidean t) s /\ a IN s /\ (!x. x IN s ==> f x = g x) /\ f continuous (at a within t) ==> g continuous (at a within t)`,
(* ------------------------------------------------------------------------- *) (* 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`,
REWRITE_TAC[CONTINUOUS_WITHIN; LIM_WITHIN] THEN REWRITE_TAC[GSYM DIST_NZ] THEN MESON_TAC[DIST_REFL]);;
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`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN REWRITE_TAC[continuous_within; IN_UNIV]);;
(* ------------------------------------------------------------------------- *) (* Versions in terms of open balls. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_WITHIN_BALL = 
prove (`!f s x. f continuous (at x within s) <=> !e. &0 < e ==> ?d. &0 < d /\ IMAGE f (ball(x,d) INTER s) SUBSET ball(f x,e)`,
let CONTINUOUS_AT_BALL = 
prove (`!f x. f continuous (at x) <=> !e. &0 < e ==> ?d. &0 < d /\ IMAGE f (ball(x,d)) SUBSET ball(f x,e)`,
SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_BALL; continuous_at] THEN MESON_TAC[DIST_SYM]);;
(* ------------------------------------------------------------------------- *) (* 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"));;
let continuous_on = new_definition
  `f continuous_on s <=>
        !x. x IN s ==> !e. &0 < e
                           ==> ?d. &0 < d /\
                                   !x'. x' IN s /\ dist(x',x) < d
                                        ==> dist(f(x'),f(x)) < e`;;
let uniformly_continuous_on = new_definition
  `f uniformly_continuous_on s <=>
        !e. &0 < e
            ==> ?d. &0 < d /\
                    !x x'. x IN s /\ x' IN s /\ dist(x',x) < d
                           ==> dist(f(x'),f(x)) < e`;;
(* ------------------------------------------------------------------------- *) (* Some simple consequential lemmas. *) (* ------------------------------------------------------------------------- *)
let UNIFORMLY_CONTINUOUS_IMP_CONTINUOUS = 
prove (`!f s. f uniformly_continuous_on s ==> f continuous_on s`,
REWRITE_TAC[uniformly_continuous_on; continuous_on] THEN MESON_TAC[]);;
let CONTINUOUS_AT_IMP_CONTINUOUS_ON = 
prove (`!f s. (!x. x IN s ==> f continuous (at x)) ==> f continuous_on s`,
REWRITE_TAC[continuous_at; continuous_on] THEN MESON_TAC[]);;
let CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN = 
prove (`!f s. f continuous_on s <=> !x. x IN s ==> f continuous (at x within s)`,
let CONTINUOUS_ON = 
prove (`!f (s:real^N->bool). f continuous_on s <=> !x. x IN s ==> (f --> f(x)) (at x within s)`,
let CONTINUOUS_ON_EQ_CONTINUOUS_AT = 
prove (`!f:real^M->real^N s. open s ==> (f continuous_on s <=> (!x. x IN s ==> f continuous (at x)))`,
let CONTINUOUS_WITHIN_SUBSET = 
prove (`!f s t x. f continuous (at x within s) /\ t SUBSET s ==> f continuous (at x within t)`,
REWRITE_TAC[CONTINUOUS_WITHIN] THEN MESON_TAC[LIM_WITHIN_SUBSET]);;
let CONTINUOUS_ON_SUBSET = 
prove (`!f s t. f continuous_on s /\ t SUBSET s ==> f continuous_on t`,
REWRITE_TAC[CONTINUOUS_ON] THEN MESON_TAC[SUBSET; LIM_WITHIN_SUBSET]);;
let UNIFORMLY_CONTINUOUS_ON_SUBSET = 
prove (`!f s t. f uniformly_continuous_on s /\ t SUBSET s ==> f uniformly_continuous_on t`,
REWRITE_TAC[uniformly_continuous_on] THEN MESON_TAC[SUBSET; LIM_WITHIN_SUBSET]);;
let CONTINUOUS_ON_INTERIOR = 
prove (`!f:real^M->real^N s x. f continuous_on s /\ x IN interior(s) ==> f continuous at x`,
REWRITE_TAC[interior; IN_ELIM_THM] THEN MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; CONTINUOUS_ON_SUBSET]);;
let CONTINUOUS_ON_EQ = 
prove (`!f g s. (!x. x IN s ==> f(x) = g(x)) /\ f continuous_on s ==> g continuous_on s`,
SIMP_TAC[continuous_on; IMP_CONJ]);;
let UNIFORMLY_CONTINUOUS_ON_EQ = 
prove (`!f g s. (!x. x IN s ==> f x = g x) /\ f uniformly_continuous_on s ==> g uniformly_continuous_on s`,
let CONTINUOUS_ON_SING = 
prove (`!f:real^M->real^N a. f continuous_on {a}`,
SIMP_TAC[continuous_on; IN_SING; FORALL_UNWIND_THM2; DIST_REFL] THEN MESON_TAC[]);;
let CONTINUOUS_ON_EMPTY = 
prove (`!f:real^M->real^N. f continuous_on {}`,
let CONTINUOUS_ON_NO_LIMPT = 
prove (`!f:real^M->real^N s. ~(?x. x limit_point_of s) ==> f continuous_on s`,
REWRITE_TAC[continuous_on; LIMPT_APPROACHABLE] THEN MESON_TAC[DIST_REFL]);;
let CONTINUOUS_ON_FINITE = 
prove (`!f:real^M->real^N s. FINITE s ==> f continuous_on s`,
let CONTRACTION_IMP_CONTINUOUS_ON = 
prove (`!f:real^M->real^N. (!x y. x IN s /\ y IN s ==> dist(f x,f y) <= dist(x,y)) ==> f continuous_on s`,
SIMP_TAC[continuous_on] THEN MESON_TAC[REAL_LET_TRANS]);;
let ISOMETRY_ON_IMP_CONTINUOUS_ON = 
prove (`!f:real^M->real^N. (!x y. x IN s /\ y IN s ==> dist(f x,f y) = dist(x,y)) ==> f continuous_on s`,
(* ------------------------------------------------------------------------- *) (* Characterization of various kinds of continuity in terms of sequences. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_WITHIN_SEQUENTIALLY = 
prove (`!f a:real^N. f continuous (at a within s) <=> !x. (!n. x(n) IN s) /\ (x --> a) sequentially ==> ((f o x) --> f(a)) sequentially`,
REPEAT GEN_TAC THEN REWRITE_TAC[continuous_within] THEN EQ_TAC THENL [REWRITE_TAC[LIM_SEQUENTIALLY; o_THM] THEN MESON_TAC[]; ALL_TAC] THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; NOT_EXISTS_THM] THEN DISCH_THEN(X_CHOOSE_THEN `e:real` (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_OF_NUM_LT; REAL_OF_NUM_LE; REAL_POS; ARITH; REAL_ARITH `&0 <= n ==> &0 < n + &1`; NOT_FORALL_THM; SKOLEM_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[NOT_IMP; FORALL_AND_THM] THEN X_GEN_TAC `y:num->real^N` THEN REWRITE_TAC[LIM_SEQUENTIALLY; o_THM] THEN STRIP_TAC THEN CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[LE_REFL]] THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC FORALL_POS_MONO_1 THEN CONJ_TAC THENL [ASM_MESON_TAC[REAL_LT_TRANS]; ALL_TAC] THEN X_GEN_TAC `n:num` THEN EXISTS_TAC `n:num` THEN X_GEN_TAC `m:num` THEN DISCH_TAC THEN MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `&1 / (&m + &1)` THEN ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[REAL_LE_INV2; real_div; REAL_ARITH `&0 <= x ==> &0 < x + &1`; REAL_POS; REAL_MUL_LID; REAL_LE_RADD; REAL_OF_NUM_LE]);;
let CONTINUOUS_AT_SEQUENTIALLY = 
prove (`!f a:real^N. f continuous (at a) <=> !x. (x --> a) sequentially ==> ((f o x) --> f(a)) sequentially`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN REWRITE_TAC[CONTINUOUS_WITHIN_SEQUENTIALLY; IN_UNIV]);;
let CONTINUOUS_ON_SEQUENTIALLY = 
prove (`!f s:real^N->bool. f continuous_on s <=> !x a. a IN s /\ (!n. x(n) IN s) /\ (x --> a) sequentially ==> ((f o x) --> f(a)) sequentially`,
let UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY = 
prove (`!f s:real^N->bool. f uniformly_continuous_on s <=> !x y. (!n. x(n) IN s) /\ (!n. y(n) IN s) /\ ((\n. x(n) - y(n)) --> vec 0) sequentially ==> ((\n. f(x(n)) - f(y(n))) --> vec 0) sequentially`,
REPEAT GEN_TAC THEN REWRITE_TAC[uniformly_continuous_on] THEN REWRITE_TAC[LIM_SEQUENTIALLY; dist; VECTOR_SUB_RZERO] THEN EQ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; NOT_EXISTS_THM] THEN DISCH_THEN(X_CHOOSE_THEN `e:real` (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_OF_NUM_LT; REAL_OF_NUM_LE; REAL_POS; ARITH; REAL_ARITH `&0 <= n ==> &0 < n + &1`; NOT_FORALL_THM; SKOLEM_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:num->real^N` THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:num->real^N` THEN REWRITE_TAC[NOT_IMP; FORALL_AND_THM] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[NORM_SUB] THEN CONJ_TAC THENL [MATCH_MP_TAC FORALL_POS_MONO_1 THEN CONJ_TAC THENL [ASM_MESON_TAC[REAL_LT_TRANS]; ALL_TAC] THEN X_GEN_TAC `n:num` THEN EXISTS_TAC `n:num` THEN X_GEN_TAC `m:num` THEN DISCH_TAC THEN MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `&1 / (&m + &1)` THEN ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[REAL_LE_INV2; real_div; REAL_ARITH `&0 <= x ==> &0 < x + &1`; REAL_POS; REAL_MUL_LID; REAL_LE_RADD; REAL_OF_NUM_LE]; EXISTS_TAC `e:real` THEN ASM_REWRITE_TAC[] THEN EXISTS_TAC `\x:num. x` THEN ASM_REWRITE_TAC[LE_REFL]]);;
let LIM_CONTINUOUS_FUNCTION = 
prove (`!f net g l. f continuous (at l) /\ (g --> l) net ==> ((\x. f(g x)) --> f l) net`,
REWRITE_TAC[tendsto; continuous_at; eventually] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Combination results for pointwise continuity. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_CONST = 
prove (`!net c. (\x. c) continuous net`,
REWRITE_TAC[continuous; LIM_CONST]);;
let CONTINUOUS_CMUL = 
prove (`!f c net. f continuous net ==> (\x. c % f(x)) continuous net`,
REWRITE_TAC[continuous; LIM_CMUL]);;
let CONTINUOUS_NEG = 
prove (`!f net. f continuous net ==> (\x. --(f x)) continuous net`,
REWRITE_TAC[continuous; LIM_NEG]);;
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]);;
let CONTINUOUS_VSUM = 
prove (`!net f s. FINITE s /\ (!a. a IN s ==> (f a) continuous net) ==> (\x. vsum s (\a. f a x)) continuous net`,
GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY; VSUM_CLAUSES; CONTINUOUS_CONST; CONTINUOUS_ADD; ETA_AX]);;
(* ------------------------------------------------------------------------- *) (* Same thing for setwise continuity. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_ON_CONST = 
prove (`!s c. (\x. c) continuous_on s`,
let CONTINUOUS_ON_CMUL = 
prove (`!f c s. f continuous_on s ==> (\x. c % f(x)) continuous_on s`,
let CONTINUOUS_ON_NEG = 
prove (`!f s. f continuous_on s ==> (\x. --(f x)) continuous_on s`,
let CONTINUOUS_ON_ADD = 
prove (`!f g s. f continuous_on s /\ g continuous_on s ==> (\x. f(x) + g(x)) continuous_on s`,
let CONTINUOUS_ON_SUB = 
prove (`!f g s. f continuous_on s /\ g continuous_on s ==> (\x. f(x) - g(x)) continuous_on s`,
let CONTINUOUS_ON_ABS = 
prove (`!f:real^M->real^N s. f continuous_on s ==> (\x. (lambda i. abs(f(x)$i)):real^N) continuous_on s`,
let CONTINUOUS_ON_MAX = 
prove (`!f:real^M->real^N g:real^M->real^N s. f continuous_on s /\ g continuous_on s ==> (\x. (lambda i. max (f(x)$i) (g(x)$i)):real^N) continuous_on s`,
let CONTINUOUS_ON_MIN = 
prove (`!f:real^M->real^N g:real^M->real^N s. f continuous_on s /\ g continuous_on s ==> (\x. (lambda i. min (f(x)$i) (g(x)$i)):real^N) continuous_on s`,
let CONTINUOUS_ON_VSUM = 
prove (`!t f s. FINITE s /\ (!a. a IN s ==> (f a) continuous_on t) ==> (\x. vsum s (\a. f a x)) continuous_on t`,
(* ------------------------------------------------------------------------- *) (* Same thing for uniform continuity, using sequential formulations. *) (* ------------------------------------------------------------------------- *)
let UNIFORMLY_CONTINUOUS_ON_CONST = 
prove (`!s c. (\x. c) uniformly_continuous_on s`,
let LINEAR_UNIFORMLY_CONTINUOUS_ON = 
prove (`!f:real^M->real^N s. linear f ==> f uniformly_continuous_on s`,
REPEAT STRIP_TAC THEN ASM_SIMP_TAC[uniformly_continuous_on; dist; GSYM LINEAR_SUB] THEN FIRST_ASSUM(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC o MATCH_MP LINEAR_BOUNDED_POS) THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `e / B:real` THEN ASM_SIMP_TAC[REAL_LT_DIV] THEN MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^M`] THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `B * norm(y - x:real^M)` THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[REAL_LT_RDIV_EQ; REAL_MUL_SYM]);;
let UNIFORMLY_CONTINUOUS_ON_COMPOSE = 
prove (`!f g s. f uniformly_continuous_on s /\ g uniformly_continuous_on (IMAGE f s) ==> (g o f) uniformly_continuous_on s`,
let lemma = prove
   (`(!y. ((?x. (y = f x) /\ P x) /\ Q y ==> R y)) <=>
     (!x. P x /\ Q (f x) ==> R (f x))`,
    MESON_TAC[]) in
  REPEAT GEN_TAC THEN
  REWRITE_TAC[uniformly_continuous_on; o_THM; IN_IMAGE] THEN
  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN REWRITE_TAC[lemma] THEN
  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN
  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN REWRITE_TAC[lemma] THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  MATCH_MP_TAC MONO_FORALL THEN
  X_GEN_TAC `e:real` THEN ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
  ASM_MESON_TAC[]);;
let BILINEAR_UNIFORMLY_CONTINUOUS_ON_COMPOSE = 
prove (`!f:real^M->real^N g (h:real^N->real^P->real^Q) s. f uniformly_continuous_on s /\ g uniformly_continuous_on s /\ bilinear h /\ bounded(IMAGE f s) /\ bounded(IMAGE g s) ==> (\x. h (f x) (g x)) uniformly_continuous_on s`,
REPEAT STRIP_TAC THEN REWRITE_TAC[uniformly_continuous_on; dist] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN SUBGOAL_THEN `!a b c d. (h:real^N->real^P->real^Q) a b - h c d = h (a - c) b + h c (b - d)` (fun th -> ONCE_REWRITE_TAC[th]) THENL [FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP BILINEAR_LSUB th]) THEN FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP BILINEAR_RSUB th]) THEN VECTOR_ARITH_TAC; ALL_TAC] THEN FIRST_X_ASSUM(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC o MATCH_MP BILINEAR_BOUNDED_POS) THEN UNDISCH_TAC `bounded(IMAGE (g:real^M->real^P) s)` THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BOUNDED_POS]) THEN REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE] THEN DISCH_THEN(X_CHOOSE_THEN `B1:real` STRIP_ASSUME_TAC) THEN DISCH_THEN(X_CHOOSE_THEN `B2:real` STRIP_ASSUME_TAC) THEN UNDISCH_TAC `(g:real^M->real^P) uniformly_continuous_on s` THEN UNDISCH_TAC `(f:real^M->real^N) uniformly_continuous_on s` THEN REWRITE_TAC[uniformly_continuous_on] THEN DISCH_THEN(MP_TAC o SPEC `e / &2 / &2 / B / B2`) THEN ASM_SIMP_TAC[REAL_LT_DIV; REAL_HALF; dist] THEN DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN DISCH_THEN(MP_TAC o SPEC `e / &2 / &2 / B / B1`) THEN ASM_SIMP_TAC[REAL_LT_DIV; REAL_HALF; dist] THEN DISCH_THEN(X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC) THEN EXISTS_TAC `min d1 d2` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^M`] THEN STRIP_TAC THEN REPEAT(FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^M`; `y:real^M`])) THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `B * e / &2 / &2 / B / B2 * B2 + B * B1 * e / &2 / &2 / B / B1` THEN CONJ_TAC THENL [MATCH_MP_TAC(NORM_ARITH `norm(x) <= a /\ norm(y) <= b ==> norm(x + y:real^N) <= a + b`) THEN CONJ_TAC THEN FIRST_X_ASSUM(fun th -> W(MP_TAC o PART_MATCH lhand th o lhand o snd)) THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN MATCH_MP_TAC REAL_LE_LMUL THEN ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_POS_LE]; ASM_SIMP_TAC[REAL_DIV_RMUL; REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN ASM_REAL_ARITH_TAC]);;
let UNIFORMLY_CONTINUOUS_ON_MUL = 
prove (`!f g:real^M->real^N s. (lift o f) uniformly_continuous_on s /\ g uniformly_continuous_on s /\ bounded(IMAGE (lift o f) s) /\ bounded(IMAGE g s) ==> (\x. f x % g x) uniformly_continuous_on s`,
REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`lift o (f:real^M->real)`; `g:real^M->real^N`; `\c (v:real^N). drop c % v`; `s:real^M->bool`] BILINEAR_UNIFORMLY_CONTINUOUS_ON_COMPOSE) THEN ASM_REWRITE_TAC[o_THM; LIFT_DROP] THEN DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[bilinear; linear; DROP_ADD; DROP_CMUL] THEN VECTOR_ARITH_TAC);;
let UNIFORMLY_CONTINUOUS_ON_CMUL = 
prove (`!f c s. f uniformly_continuous_on s ==> (\x. c % f(x)) uniformly_continuous_on s`,
REPEAT GEN_TAC THEN REWRITE_TAC[UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY] THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_CMUL) THEN ASM_SIMP_TAC[VECTOR_SUB_LDISTRIB; VECTOR_MUL_RZERO]);;
let UNIFORMLY_CONTINUOUS_ON_VMUL = 
prove (`!s:real^M->bool c v:real^N. (lift o c) uniformly_continuous_on s ==> (\x. c x % v) uniformly_continuous_on s`,
REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o ISPEC `\x. (drop x % v:real^N)` o MATCH_MP (REWRITE_RULE[IMP_CONJ] UNIFORMLY_CONTINUOUS_ON_COMPOSE)) THEN REWRITE_TAC[o_DEF; LIFT_DROP] THEN DISCH_THEN MATCH_MP_TAC THEN MATCH_MP_TAC LINEAR_UNIFORMLY_CONTINUOUS_ON THEN MATCH_MP_TAC LINEAR_VMUL_DROP THEN REWRITE_TAC[LINEAR_ID]);;
let UNIFORMLY_CONTINUOUS_ON_NEG = 
prove (`!f s. f uniformly_continuous_on s ==> (\x. --(f x)) uniformly_continuous_on s`,
ONCE_REWRITE_TAC[VECTOR_NEG_MINUS1] THEN REWRITE_TAC[UNIFORMLY_CONTINUOUS_ON_CMUL]);;
let UNIFORMLY_CONTINUOUS_ON_ADD = 
prove (`!f g s. f uniformly_continuous_on s /\ g uniformly_continuous_on s ==> (\x. f(x) + g(x)) uniformly_continuous_on s`,
REPEAT GEN_TAC THEN REWRITE_TAC[UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY] THEN REWRITE_TAC[AND_FORALL_THM] THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[o_DEF] THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_ADD) THEN MATCH_MP_TAC EQ_IMP THEN REWRITE_TAC[VECTOR_ADD_LID] THEN AP_THM_TAC THEN BINOP_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN VECTOR_ARITH_TAC);;
let UNIFORMLY_CONTINUOUS_ON_SUB = 
prove (`!f g s. f uniformly_continuous_on s /\ g uniformly_continuous_on s ==> (\x. f(x) - g(x)) uniformly_continuous_on s`,
let UNIFORMLY_CONTINUOUS_ON_VSUM = 
prove (`!t f s. FINITE s /\ (!a. a IN s ==> (f a) uniformly_continuous_on t) ==> (\x. vsum s (\a. f a x)) uniformly_continuous_on t`,
GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY; VSUM_CLAUSES; UNIFORMLY_CONTINUOUS_ON_CONST; UNIFORMLY_CONTINUOUS_ON_ADD; ETA_AX]);;
(* ------------------------------------------------------------------------- *) (* Identity function is continuous in every sense. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_WITHIN_ID = 
prove (`!a s. (\x. x) continuous (at a within s)`,
REWRITE_TAC[continuous_within] THEN MESON_TAC[]);;
let CONTINUOUS_AT_ID = 
prove (`!a. (\x. x) continuous (at a)`,
REWRITE_TAC[continuous_at] THEN MESON_TAC[]);;
let CONTINUOUS_ON_ID = 
prove (`!s. (\x. x) continuous_on s`,
REWRITE_TAC[continuous_on] THEN MESON_TAC[]);;
let UNIFORMLY_CONTINUOUS_ON_ID = 
prove (`!s. (\x. x) uniformly_continuous_on s`,
REWRITE_TAC[uniformly_continuous_on] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Continuity of all kinds is preserved under composition. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_WITHIN_COMPOSE = 
prove (`!f g x s. f continuous (at x within s) /\ g continuous (at (f x) within IMAGE f s) ==> (g o f) continuous (at x within s)`,
REPEAT GEN_TAC THEN REWRITE_TAC[continuous_within; o_THM; IN_IMAGE] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN ASM_MESON_TAC[]);;
let CONTINUOUS_AT_COMPOSE = 
prove (`!f g x. f continuous (at x) /\ g continuous (at (f x)) ==> (g o f) continuous (at x)`,
let CONTINUOUS_ON_COMPOSE = 
prove (`!f g s. f continuous_on s /\ g continuous_on (IMAGE f s) ==> (g o f) continuous_on s`,
(* ------------------------------------------------------------------------- *) (* Continuity in terms of open preimages. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_WITHIN_OPEN = 
prove (`!f:real^M->real^N x u. f continuous (at x within u) <=> !t. open t /\ f(x) IN t ==> ?s. open s /\ x IN s /\ !x'. x' IN s /\ x' IN u ==> f(x') IN t`,
REPEAT GEN_TAC THEN REWRITE_TAC[continuous_within] THEN EQ_TAC THENL [DISCH_TAC THEN X_GEN_TAC `t:real^N->bool` THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN GEN_REWRITE_TAC LAND_CONV [open_def] THEN DISCH_THEN(MP_TAC o SPEC `(f:real^M->real^N) x`) THEN ASM_MESON_TAC[IN_BALL; DIST_SYM; OPEN_BALL; CENTRE_IN_BALL; DIST_SYM]; DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `ball((f:real^M->real^N) x,e)`) THEN ASM_SIMP_TAC[OPEN_BALL; CENTRE_IN_BALL] THEN MESON_TAC[open_def; IN_BALL; REAL_LT_TRANS; DIST_SYM]]);;
let CONTINUOUS_AT_OPEN = 
prove (`!f:real^M->real^N x. f continuous (at x) <=> !t. open t /\ f(x) IN t ==> ?s. open s /\ x IN s /\ !x'. x' IN s ==> f(x') IN t`,
REPEAT GEN_TAC THEN REWRITE_TAC[continuous_at] THEN EQ_TAC THENL [DISCH_TAC THEN X_GEN_TAC `t:real^N->bool` THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN GEN_REWRITE_TAC LAND_CONV [open_def] THEN DISCH_THEN(MP_TAC o SPEC `(f:real^M->real^N) x`) THEN ASM_MESON_TAC[IN_BALL; DIST_SYM; OPEN_BALL; CENTRE_IN_BALL]; DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `ball((f:real^M->real^N) x,e)`) THEN ASM_SIMP_TAC[OPEN_BALL; CENTRE_IN_BALL] THEN MESON_TAC[open_def; IN_BALL; REAL_LT_TRANS; DIST_SYM]]);;
let CONTINUOUS_ON_OPEN_GEN = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> (f continuous_on s <=> !u. open_in (subtopology euclidean t) u ==> open_in (subtopology euclidean s) {x | x IN s /\ f x IN u})`,
REPEAT STRIP_TAC THEN REWRITE_TAC[continuous_on] THEN EQ_TAC THENL [REWRITE_TAC[open_in; SUBSET; IN_ELIM_THM] THEN DISCH_TAC THEN X_GEN_TAC `u:real^N->bool` THEN STRIP_TAC THEN CONJ_TAC THENL [ASM_MESON_TAC[DIST_REFL]; ALL_TAC] THEN X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `(f:real^M->real^N) x`) THEN ASM SET_TAC[]; DISCH_TAC THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `ball((f:real^M->real^N) x,e) INTER t`) THEN ANTS_TAC THENL [ASM_MESON_TAC[OPEN_IN_OPEN; INTER_COMM; OPEN_BALL]; ALL_TAC] THEN REWRITE_TAC[open_in; SUBSET; IN_INTER; IN_ELIM_THM; IN_BALL; IN_IMAGE] THEN REWRITE_TAC[AND_FORALL_THM] THEN DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE]) THEN ASM_MESON_TAC[DIST_REFL; DIST_SYM]]);;
let CONTINUOUS_ON_OPEN = 
prove (`!f:real^M->real^N s. f continuous_on s <=> !t. open_in (subtopology euclidean (IMAGE f s)) t ==> open_in (subtopology euclidean s) {x | x IN s /\ f(x) IN t}`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_OPEN_GEN THEN REWRITE_TAC[SUBSET_REFL]);;
let CONTINUOUS_OPEN_IN_PREIMAGE_GEN = 
prove (`!f:real^M->real^N s t u. f continuous_on s /\ IMAGE f s SUBSET t /\ open_in (subtopology euclidean t) u ==> open_in (subtopology euclidean s) {x | x IN s /\ f x IN u}`,
MESON_TAC[CONTINUOUS_ON_OPEN_GEN]);;
let CONTINUOUS_ON_IMP_OPEN_IN = 
prove (`!f:real^M->real^N s t. f continuous_on s /\ open_in (subtopology euclidean (IMAGE f s)) t ==> open_in (subtopology euclidean s) {x | x IN s /\ f x IN t}`,
MESON_TAC[CONTINUOUS_ON_OPEN]);;
(* ------------------------------------------------------------------------- *) (* Similarly in terms of closed sets. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_ON_CLOSED_GEN = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> (f continuous_on s <=> !u. closed_in (subtopology euclidean t) u ==> closed_in (subtopology euclidean s) {x | x IN s /\ f x IN u})`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(fun th -> ONCE_REWRITE_TAC[MATCH_MP CONTINUOUS_ON_OPEN_GEN th]) THEN EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `u:real^N->bool` THEN FIRST_X_ASSUM(MP_TAC o SPEC `t DIFF u:real^N->bool`) THENL [REWRITE_TAC[closed_in]; REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ]] THEN REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[SUBSET_RESTRICT] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]);;
let CONTINUOUS_ON_CLOSED = 
prove (`!f:real^M->real^N s. f continuous_on s <=> !t. closed_in (subtopology euclidean (IMAGE f s)) t ==> closed_in (subtopology euclidean s) {x | x IN s /\ f(x) IN t}`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_CLOSED_GEN THEN REWRITE_TAC[SUBSET_REFL]);;
let CONTINUOUS_CLOSED_IN_PREIMAGE_GEN = 
prove (`!f:real^M->real^N s t u. f continuous_on s /\ IMAGE f s SUBSET t /\ closed_in (subtopology euclidean t) u ==> closed_in (subtopology euclidean s) {x | x IN s /\ f x IN u}`,
let CONTINUOUS_ON_IMP_CLOSED_IN = 
prove (`!f:real^M->real^N s t. f continuous_on s /\ closed_in (subtopology euclidean (IMAGE f s)) t ==> closed_in (subtopology euclidean s) {x | x IN s /\ f x IN t}`,
MESON_TAC[CONTINUOUS_ON_CLOSED]);;
(* ------------------------------------------------------------------------- *) (* Half-global and completely global cases. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_OPEN_IN_PREIMAGE = 
prove (`!f s t. f continuous_on s /\ open t ==> open_in (subtopology euclidean s) {x | x IN s /\ f x IN t}`,
REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[SET_RULE `x IN s /\ f x IN t <=> x IN s /\ f x IN (t INTER IMAGE f s)`] THEN FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[CONTINUOUS_ON_OPEN]) THEN ONCE_REWRITE_TAC[INTER_COMM] THEN MATCH_MP_TAC OPEN_IN_OPEN_INTER THEN ASM_REWRITE_TAC[]);;
let CONTINUOUS_CLOSED_IN_PREIMAGE = 
prove (`!f s t. f continuous_on s /\ closed t ==> closed_in (subtopology euclidean s) {x | x IN s /\ f x IN t}`,
REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[SET_RULE `x IN s /\ f x IN t <=> x IN s /\ f x IN (t INTER IMAGE f s)`] THEN FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[CONTINUOUS_ON_CLOSED]) THEN ONCE_REWRITE_TAC[INTER_COMM] THEN MATCH_MP_TAC CLOSED_IN_CLOSED_INTER THEN ASM_REWRITE_TAC[]);;
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]]]);;
let CONTINUOUS_CLOSED_PREIMAGE = 
prove (`!f:real^M->real^N s t. f continuous_on s /\ closed s /\ closed t ==> closed {x | x IN s /\ f(x) IN t}`,
REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONTINUOUS_ON_CLOSED]) THEN REWRITE_TAC [CLOSED_IN_CLOSED] 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 [CLOSED_INTER]]]);;
let CONTINUOUS_OPEN_PREIMAGE_UNIV = 
prove (`!f:real^M->real^N s. (!x. f continuous (at x)) /\ open s ==> open {x | f(x) IN s}`,
REPEAT STRIP_TAC THEN MP_TAC(SPECL [`f:real^M->real^N`; `(:real^M)`; `s:real^N->bool`] CONTINUOUS_OPEN_PREIMAGE) THEN ASM_SIMP_TAC[OPEN_UNIV; IN_UNIV; CONTINUOUS_AT_IMP_CONTINUOUS_ON]);;
let CONTINUOUS_CLOSED_PREIMAGE_UNIV = 
prove (`!f:real^M->real^N s. (!x. f continuous (at x)) /\ closed s ==> closed {x | f(x) IN s}`,
REPEAT STRIP_TAC THEN MP_TAC(SPECL [`f:real^M->real^N`; `(:real^M)`; `s:real^N->bool`] CONTINUOUS_CLOSED_PREIMAGE) THEN ASM_SIMP_TAC[CLOSED_UNIV; IN_UNIV; CONTINUOUS_AT_IMP_CONTINUOUS_ON]);;
let CONTINUOUS_OPEN_IN_PREIMAGE_EQ = 
prove (`!f:real^M->real^N s. f continuous_on s <=> !t. open t ==> open_in (subtopology euclidean s) {x | x IN s /\ f x IN t}`,
REPEAT GEN_TAC THEN EQ_TAC THEN SIMP_TAC[CONTINUOUS_OPEN_IN_PREIMAGE] THEN REWRITE_TAC[CONTINUOUS_ON_OPEN] THEN DISCH_TAC THEN X_GEN_TAC `t:real^N->bool` THEN GEN_REWRITE_TAC LAND_CONV [OPEN_IN_OPEN] THEN DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN FIRST_X_ASSUM(MP_TAC o SPEC `u:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN SET_TAC[]);;
let CONTINUOUS_CLOSED_IN_PREIMAGE_EQ = 
prove (`!f:real^M->real^N s. f continuous_on s <=> !t. closed t ==> closed_in (subtopology euclidean s) {x | x IN s /\ f x IN t}`,
REPEAT GEN_TAC THEN EQ_TAC THEN SIMP_TAC[CONTINUOUS_CLOSED_IN_PREIMAGE] THEN REWRITE_TAC[CONTINUOUS_ON_CLOSED] THEN DISCH_TAC THEN X_GEN_TAC `t:real^N->bool` THEN GEN_REWRITE_TAC LAND_CONV [CLOSED_IN_CLOSED] THEN DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN FIRST_X_ASSUM(MP_TAC o SPEC `u:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN SET_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Linear functions are (uniformly) continuous on any set. *) (* ------------------------------------------------------------------------- *)
let LINEAR_LIM_0 = 
prove (`!f. linear f ==> (f --> vec 0) (at (vec 0))`,
REPEAT STRIP_TAC THEN REWRITE_TAC[LIM_AT] THEN FIRST_X_ASSUM(MP_TAC o MATCH_MP LINEAR_BOUNDED_POS) THEN DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `e / B` THEN ASM_SIMP_TAC[REAL_LT_DIV] THEN REWRITE_TAC[dist; VECTOR_SUB_RZERO] THEN ASM_MESON_TAC[REAL_MUL_SYM; REAL_LET_TRANS; REAL_LT_RDIV_EQ]);;
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[]);;
let LINEAR_CONTINUOUS_WITHIN = 
prove (`!f:real^M->real^N s x. linear f ==> f continuous (at x within s)`,
let LINEAR_CONTINUOUS_ON = 
prove (`!f:real^M->real^N s. linear f ==> f continuous_on s`,
let LINEAR_CONTINUOUS_COMPOSE = 
prove (`!net f:A->real^N g:real^N->real^P. f continuous net /\ linear g ==> (\x. g(f x)) continuous net`,
REWRITE_TAC[continuous; LIM_LINEAR]);;
let LINEAR_CONTINUOUS_ON_COMPOSE = 
prove (`!f:real^M->real^N g:real^N->real^P s. f continuous_on s /\ linear g ==> (\x. g(f x)) continuous_on s`,
let CONTINUOUS_LIFT_COMPONENT_COMPOSE = 
prove (`!net f:A->real^N i. f continuous net ==> (\x. lift(f x$i)) continuous net`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `linear(\x:real^N. lift (x$i))` MP_TAC THENL [REWRITE_TAC[LINEAR_LIFT_COMPONENT]; REWRITE_TAC[GSYM IMP_CONJ_ALT]] THEN REWRITE_TAC[LINEAR_CONTINUOUS_COMPOSE]);;
let CONTINUOUS_ON_LIFT_COMPONENT_COMPOSE = 
prove (`!f:real^M->real^N s. f continuous_on s ==> (\x. lift (f x$i)) continuous_on s`,
(* ------------------------------------------------------------------------- *) (* 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`,
REWRITE_TAC[continuous; LIM_BILINEAR]);;
let BILINEAR_CONTINUOUS_ON_COMPOSE = 
prove (`!f g h s. f continuous_on s /\ g continuous_on s /\ bilinear h ==> (\x. h (f x) (g x)) continuous_on s`,
let BILINEAR_DOT = 
prove (`bilinear (\x y:real^N. lift(x dot y))`,
REWRITE_TAC[bilinear; linear; DOT_LADD; DOT_RADD; DOT_LMUL; DOT_RMUL] THEN REWRITE_TAC[LIFT_ADD; LIFT_CMUL]);;
let CONTINUOUS_LIFT_DOT2 = 
prove (`!net f g:A->real^N. f continuous net /\ g continuous net ==> (\x. lift(f x dot g x)) continuous net`,
REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP (MATCH_MP (REWRITE_RULE [TAUT `p /\ q /\ r ==> s <=> r ==> p /\ q ==> s`] BILINEAR_CONTINUOUS_COMPOSE) BILINEAR_DOT)) THEN REWRITE_TAC[]);;
let CONTINUOUS_ON_LIFT_DOT2 = 
prove (`!f:real^M->real^N g s. f continuous_on s /\ g continuous_on s ==> (\x. lift(f x dot g x)) continuous_on s`,
REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP (MATCH_MP (REWRITE_RULE [TAUT `p /\ q /\ r ==> s <=> r ==> p /\ q ==> s`] BILINEAR_CONTINUOUS_ON_COMPOSE) BILINEAR_DOT)) THEN REWRITE_TAC[]);;
(* ------------------------------------------------------------------------- *) (* 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[]);;
let COMPACT_TRANSLATION = 
prove (`!s a:real^N. compact s ==> compact (IMAGE (\x. a + x) s)`,
let COMPACT_TRANSLATION_EQ = 
prove (`!a s. compact (IMAGE (\x:real^N. a + x) s) <=> compact s`,
REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[COMPACT_TRANSLATION] THEN DISCH_THEN(MP_TAC o ISPEC `--a:real^N` o MATCH_MP COMPACT_TRANSLATION) THEN REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID; VECTOR_ARITH `--a + a + x:real^N = x`]);;
add_translation_invariants [COMPACT_TRANSLATION_EQ];;
let COMPACT_LINEAR_IMAGE = 
prove (`!f:real^M->real^N s. compact s /\ linear f ==> compact(IMAGE f s)`,
let COMPACT_LINEAR_IMAGE_EQ = 
prove (`!f s. linear f /\ (!x y. f x = f y ==> x = y) ==> (compact (IMAGE f s) <=> compact s)`,
MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE COMPACT_LINEAR_IMAGE));;
add_linear_invariants [COMPACT_LINEAR_IMAGE_EQ];;
let CONNECTED_CONTINUOUS_IMAGE = 
prove (`!f:real^M->real^N s. f continuous_on s /\ connected s ==> connected(IMAGE f s)`,
REPEAT GEN_TAC THEN REWRITE_TAC[CONTINUOUS_ON_OPEN] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[CONNECTED_CLOPEN; NOT_FORALL_THM; NOT_IMP; DE_MORGAN_THM] THEN REWRITE_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN FIRST_X_ASSUM(fun th -> MP_TAC(SPEC `t:real^N->bool` th) THEN MP_TAC(SPEC `IMAGE (f:real^M->real^N) s DIFF t` th)) THEN ASM_REWRITE_TAC[] THEN SUBGOAL_THEN `{x | x IN s /\ (f:real^M->real^N) x IN IMAGE f s DIFF t} = s DIFF {x | x IN s /\ f x IN t}` SUBST1_TAC THENL [UNDISCH_TAC `t SUBSET IMAGE (f:real^M->real^N) s` THEN REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DIFF; IN_ELIM_THM; SUBSET] THEN MESON_TAC[]; REPEAT STRIP_TAC THEN EXISTS_TAC `{x | x IN s /\ (f:real^M->real^N) x IN t}` THEN ASM_REWRITE_TAC[] THEN POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN REWRITE_TAC[IN_IMAGE; SUBSET; IN_ELIM_THM; NOT_IN_EMPTY; EXTENSION] THEN MESON_TAC[]]);;
let CONNECTED_TRANSLATION = 
prove (`!a s. connected s ==> connected (IMAGE (\x:real^N. a + x) s)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN ASM_SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST]);;
let CONNECTED_TRANSLATION_EQ = 
prove (`!a s. connected (IMAGE (\x:real^N. a + x) s) <=> connected s`,
REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[CONNECTED_TRANSLATION] THEN DISCH_THEN(MP_TAC o ISPEC `--a:real^N` o MATCH_MP CONNECTED_TRANSLATION) THEN REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID; VECTOR_ARITH `--a + a + x:real^N = x`]);;
add_translation_invariants [CONNECTED_TRANSLATION_EQ];;
let CONNECTED_LINEAR_IMAGE = 
prove (`!f:real^M->real^N s. connected s /\ linear f ==> connected(IMAGE f s)`,
let CONNECTED_LINEAR_IMAGE_EQ = 
prove (`!f s. linear f /\ (!x y. f x = f y ==> x = y) ==> (connected (IMAGE f s) <=> connected s)`,
MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE CONNECTED_LINEAR_IMAGE));;
add_linear_invariants [CONNECTED_LINEAR_IMAGE_EQ];; (* ------------------------------------------------------------------------- *) (* Preservation properties for pasted sets (Cartesian products). *) (* ------------------------------------------------------------------------- *)
let BOUNDED_PCROSS_EQ = 
prove (`!s:real^M->bool t:real^N->bool. bounded (s PCROSS t) <=> s = {} \/ t = {} \/ bounded s /\ bounded t`,
REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS] THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN ASM_CASES_TAC `t:real^N->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN REWRITE_TAC[SET_RULE `{f x y |x,y| F} = {}`; BOUNDED_EMPTY] THEN RULE_ASSUM_TAC(REWRITE_RULE[GSYM MEMBER_NOT_EMPTY]) THEN REWRITE_TAC[bounded; FORALL_PASTECART; IN_ELIM_PASTECART_THM] THEN ASM_MESON_TAC[NORM_LE_PASTECART; REAL_LE_TRANS; NORM_PASTECART_LE; REAL_LE_ADD2]);;
let BOUNDED_PCROSS = 
prove (`!s:real^M->bool t:real^N->bool. bounded s /\ bounded t ==> bounded (s PCROSS t)`,
SIMP_TAC[BOUNDED_PCROSS_EQ]);;
let CLOSED_PCROSS_EQ = 
prove (`!s:real^M->bool t:real^N->bool. closed (s PCROSS t) <=> s = {} \/ t = {} \/ closed s /\ closed t`,
REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS] THEN MAP_EVERY ASM_CASES_TAC [`s:real^M->bool = {}`; `t:real^N->bool = {}`] THEN ASM_REWRITE_TAC[NOT_IN_EMPTY; CLOSED_EMPTY; SET_RULE `{f x y |x,y| F} = {}`] THEN REWRITE_TAC[CLOSED_SEQUENTIAL_LIMITS; LIM_SEQUENTIALLY] THEN REWRITE_TAC[FORALL_PASTECART; IN_ELIM_PASTECART_THM] THEN REWRITE_TAC[IN_ELIM_THM; SKOLEM_THM; FORALL_AND_THM] THEN ONCE_REWRITE_TAC[GSYM FUN_EQ_THM] THEN REWRITE_TAC[LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN SIMP_TAC[TAUT `((p /\ q) /\ r) /\ s ==> t <=> r ==> p /\ q /\ s ==> t`] THEN ONCE_REWRITE_TAC[MESON[] `(!a b c d e. P a b c d e) <=> (!d e b c a. P a b c d e)`] THEN REWRITE_TAC[FORALL_UNWIND_THM2] THEN RULE_ASSUM_TAC(REWRITE_RULE[GSYM MEMBER_NOT_EMPTY]) THEN EQ_TAC THENL [GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [TAUT `p ==> q /\ r <=> (p ==> q) /\ (p ==> r)`; FORALL_AND_THM] THEN MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL [ALL_TAC; GEN_REWRITE_TAC LAND_CONV [SWAP_FORALL_THM]] THEN MATCH_MP_TAC MONO_FORALL THEN REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN MATCH_MP_TAC(MESON[] `(?x. P x (\n. x)) ==> (?s x. P x s)`) THEN ASM_MESON_TAC[DIST_PASTECART_CANCEL]; ONCE_REWRITE_TAC[MESON[] `(!x l. P x l) /\ (!y m. Q y m) <=> (!x y l m. P x l /\ Q y m)`] THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN REWRITE_TAC[dist; PASTECART_SUB] THEN ASM_MESON_TAC[NORM_LE_PASTECART; REAL_LET_TRANS]]);;
let CLOSED_PCROSS = 
prove (`!s:real^M->bool t:real^N->bool. closed s /\ closed t ==> closed (s PCROSS t)`,
SIMP_TAC[CLOSED_PCROSS_EQ]);;
let COMPACT_PCROSS_EQ = 
prove (`!s:real^M->bool t:real^N->bool. compact (s PCROSS t) <=> s = {} \/ t = {} \/ compact s /\ compact t`,
let COMPACT_PCROSS = 
prove (`!s:real^M->bool t:real^N->bool. compact s /\ compact t ==> compact (s PCROSS t)`,
SIMP_TAC[COMPACT_PCROSS_EQ]);;
let OPEN_PCROSS_EQ = 
prove (`!s:real^M->bool t:real^N->bool. open (s PCROSS t) <=> s = {} \/ t = {} \/ open s /\ open t`,
REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS] THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN ASM_CASES_TAC `t:real^N->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN REWRITE_TAC[SET_RULE `{f x y |x,y| F} = {}`; OPEN_EMPTY] THEN RULE_ASSUM_TAC(REWRITE_RULE[GSYM MEMBER_NOT_EMPTY]) THEN EQ_TAC THENL [REWRITE_TAC[open_def; FORALL_PASTECART; IN_ELIM_PASTECART_THM] THEN ASM_MESON_TAC[DIST_PASTECART_CANCEL]; REWRITE_TAC[OPEN_CLOSED] THEN STRIP_TAC THEN SUBGOAL_THEN `UNIV DIFF {pastecart x y | x IN s /\ y IN t} = {pastecart x y | x IN ((:real^M) DIFF s) /\ y IN (:real^N)} UNION {pastecart x y | x IN (:real^M) /\ y IN ((:real^N) DIFF t)}` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_DIFF; IN_UNION; FORALL_PASTECART; IN_UNIV] THEN REWRITE_TAC[IN_ELIM_THM; PASTECART_EQ; FSTCART_PASTECART; SNDCART_PASTECART] THEN MESON_TAC[]; SIMP_TAC[GSYM PCROSS] THEN MATCH_MP_TAC CLOSED_UNION THEN CONJ_TAC THEN MATCH_MP_TAC CLOSED_PCROSS THEN ASM_REWRITE_TAC[CLOSED_UNIV]]]);;
let OPEN_PCROSS = 
prove (`!s:real^M->bool t:real^N->bool. open s /\ open t ==> open (s PCROSS t)`,
SIMP_TAC[OPEN_PCROSS_EQ]);;
let OPEN_IN_PCROSS = 
prove (`!s s':real^M->bool t t':real^N->bool. open_in (subtopology euclidean s) s' /\ open_in (subtopology euclidean t) t' ==> open_in (subtopology euclidean (s PCROSS t)) (s' PCROSS t')`,
REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_OPEN] THEN DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `s'':real^M->bool` STRIP_ASSUME_TAC) (X_CHOOSE_THEN `t'':real^N->bool` STRIP_ASSUME_TAC)) THEN EXISTS_TAC `(s'':real^M->bool) PCROSS (t'':real^N->bool)` THEN ASM_SIMP_TAC[OPEN_PCROSS; EXTENSION; FORALL_PASTECART] THEN REWRITE_TAC[IN_INTER; PASTECART_IN_PCROSS] THEN ASM SET_TAC[]);;
let PASTECART_IN_INTERIOR_SUBTOPOLOGY = 
prove (`!s t u x:real^M y:real^N. pastecart x y IN u /\ open_in (subtopology euclidean (s PCROSS t)) u ==> ?v w. open_in (subtopology euclidean s) v /\ x IN v /\ open_in (subtopology euclidean t) w /\ y IN w /\ (v PCROSS w) SUBSET u`,
REWRITE_TAC[open_in; FORALL_PASTECART; PASTECART_IN_PCROSS] THEN REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^M`; `y:real^N`]) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN EXISTS_TAC `ball(x:real^M,e / &2) INTER s` THEN EXISTS_TAC `ball(y:real^N,e / &2) INTER t` THEN SUBGOAL_THEN `(x:real^M) IN s /\ (y:real^N) IN t` STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[SUBSET; PASTECART_IN_PCROSS]; ALL_TAC] THEN ASM_SIMP_TAC[INTER_SUBSET; IN_INTER; CENTRE_IN_BALL; REAL_HALF] THEN REWRITE_TAC[IN_BALL] THEN REPEAT(CONJ_TAC THENL [MESON_TAC[REAL_SUB_LT; NORM_ARITH `dist(x,y) < e /\ dist(z,y) < e - dist(x,y) ==> dist(x:real^N,z) < e`]; ALL_TAC]) THEN REWRITE_TAC[SUBSET; FORALL_PASTECART; PASTECART_IN_PCROSS] THEN REWRITE_TAC[IN_BALL; IN_INTER] THEN REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[dist; PASTECART_SUB] THEN W(MP_TAC o PART_MATCH lhand NORM_PASTECART_LE o lhand o snd) THEN REWRITE_TAC[GSYM(ONCE_REWRITE_RULE[DIST_SYM] dist)] THEN ASM_REAL_ARITH_TAC);;
let OPEN_IN_PCROSS_EQ = 
prove (`!s s':real^M->bool t t':real^N->bool. open_in (subtopology euclidean (s PCROSS t)) (s' PCROSS t') <=> s' = {} \/ t' = {} \/ open_in (subtopology euclidean s) s' /\ open_in (subtopology euclidean t) t'`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `s':real^M->bool = {}` THEN ASM_REWRITE_TAC[PCROSS_EMPTY; OPEN_IN_EMPTY] THEN ASM_CASES_TAC `t':real^N->bool = {}` THEN ASM_REWRITE_TAC[PCROSS_EMPTY; OPEN_IN_EMPTY] THEN EQ_TAC THEN REWRITE_TAC[OPEN_IN_PCROSS] THEN REPEAT STRIP_TAC THENL [ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN UNDISCH_TAC `~(t':real^N->bool = {})` THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN DISCH_THEN(X_CHOOSE_TAC `y:real^N`); ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN UNDISCH_TAC `~(s':real^M->bool = {})` THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN DISCH_THEN(X_CHOOSE_TAC `x:real^M`)] THEN MP_TAC(ISPECL [`s:real^M->bool`; `t:real^N->bool`; `(s':real^M->bool) PCROSS (t':real^N->bool)`; `x:real^M`; `y:real^N`] PASTECART_IN_INTERIOR_SUBTOPOLOGY) THEN ASM_REWRITE_TAC[SUBSET; FORALL_PASTECART; PASTECART_IN_PCROSS] THEN MESON_TAC[]);;
let INTERIOR_PCROSS = 
prove (`!s:real^M->bool t:real^N->bool. interior (s PCROSS t) = (interior s) PCROSS (interior t)`,
REPEAT GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL [REWRITE_TAC[SUBSET; FORALL_PASTECART; PASTECART_IN_PCROSS] THEN MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^N`] THEN DISCH_TAC THEN MP_TAC(ISPECL [`(:real^M)`; `(:real^N)`; `interior((s:real^M->bool) PCROSS (t:real^N->bool))`; `x:real^M`; `y:real^N`] PASTECART_IN_INTERIOR_SUBTOPOLOGY) THEN REWRITE_TAC[UNIV_PCROSS_UNIV; SUBTOPOLOGY_UNIV; GSYM OPEN_IN] THEN ASM_REWRITE_TAC[OPEN_INTERIOR] THEN STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP (MESON[INTERIOR_SUBSET; SUBSET_TRANS] `s SUBSET interior t ==> s SUBSET t`)) THEN REWRITE_TAC[SUBSET_PCROSS] THEN ASM_MESON_TAC[NOT_IN_EMPTY; INTERIOR_MAXIMAL; SUBSET]; MATCH_MP_TAC INTERIOR_MAXIMAL THEN SIMP_TAC[OPEN_PCROSS; OPEN_INTERIOR; PCROSS_MONO; INTERIOR_SUBSET]]);;
(* ------------------------------------------------------------------------- *) (* Quotient maps are occasionally useful. *) (* ------------------------------------------------------------------------- *)
let QUASICOMPACT_OPEN_CLOSED = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> ((!u. u SUBSET t ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN u} ==> open_in (subtopology euclidean t) u)) <=> (!u. u SUBSET t ==> (closed_in (subtopology euclidean s) {x | x IN s /\ f x IN u} ==> closed_in (subtopology euclidean t) u)))`,
SIMP_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `u:real^N->bool` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `t DIFF u:real^N->bool`) THEN ASM_SIMP_TAC[SET_RULE `u SUBSET t ==> t DIFF (t DIFF u) = u`] THEN (ANTS_TAC THENL [SET_TAC[]; REPEAT STRIP_TAC]) THEN FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[SUBSET_RESTRICT] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[] `open_in top x ==> x = y ==> open_in top y`)) THEN ASM SET_TAC[]);;
let QUOTIENT_MAP_IMP_CONTINUOUS_OPEN = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t /\ (!u. u SUBSET t ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=> open_in (subtopology euclidean t) u)) ==> f continuous_on s`,
let QUOTIENT_MAP_IMP_CONTINUOUS_CLOSED = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t /\ (!u. u SUBSET t ==> (closed_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=> closed_in (subtopology euclidean t) u)) ==> f continuous_on s`,
let OPEN_MAP_IMP_QUOTIENT_MAP = 
prove (`!f:real^M->real^N s. f continuous_on s /\ (!t. open_in (subtopology euclidean s) t ==> open_in (subtopology euclidean (IMAGE f s)) (IMAGE f t)) ==> !t. t SUBSET IMAGE f s ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN t} <=> open_in (subtopology euclidean (IMAGE f s)) t)`,
REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL [SUBGOAL_THEN `t = IMAGE f {x | x IN s /\ (f:real^M->real^N) x IN t}` SUBST1_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[]]; FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONTINUOUS_ON_OPEN]) THEN ASM_SIMP_TAC[]]);;
let CLOSED_MAP_IMP_QUOTIENT_MAP = 
prove (`!f:real^M->real^N s. f continuous_on s /\ (!t. closed_in (subtopology euclidean s) t ==> closed_in (subtopology euclidean (IMAGE f s)) (IMAGE f t)) ==> !t. t SUBSET IMAGE f s ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN t} <=> open_in (subtopology euclidean (IMAGE f s)) t)`,
REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL [FIRST_X_ASSUM(MP_TAC o SPEC `s DIFF {x | x IN s /\ (f:real^M->real^N) x IN t}`) THEN ANTS_TAC THENL [MATCH_MP_TAC CLOSED_IN_DIFF THEN ASM_SIMP_TAC[CLOSED_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; SUBSET_UNIV]; REWRITE_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN DISCH_THEN(MP_TAC o CONJUNCT2) THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]]; FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONTINUOUS_ON_OPEN]) THEN ASM_SIMP_TAC[]]);;
let CONTINUOUS_RIGHT_INVERSE_IMP_QUOTIENT_MAP = 
prove (`!f:real^M->real^N g s t. f continuous_on s /\ IMAGE f s SUBSET t /\ g continuous_on t /\ IMAGE g t SUBSET s /\ (!y. y IN t ==> f(g y) = y) ==> (!u. u SUBSET t ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=> open_in (subtopology euclidean t) u))`,
REWRITE_TAC[CONTINUOUS_ON_OPEN] THEN REPEAT STRIP_TAC THEN EQ_TAC THENL [DISCH_TAC THEN FIRST_ASSUM(MP_TAC o SPEC `(IMAGE (g:real^N->real^M) t) INTER {x | x IN s /\ (f:real^M->real^N) x IN u}`) THEN ANTS_TAC THENL [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_OPEN]) THEN REWRITE_TAC[OPEN_IN_OPEN] THEN MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[]; MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]]; DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN SUBGOAL_THEN `IMAGE (f:real^M->real^N) s = t` (fun th -> ASM_REWRITE_TAC[th]) THEN ASM SET_TAC[]]);;
let CONTINUOUS_LEFT_INVERSE_IMP_QUOTIENT_MAP = 
prove (`!f:real^M->real^N g s. f continuous_on s /\ g continuous_on (IMAGE f s) /\ (!x. x IN s ==> g(f x) = x) ==> (!u. u SUBSET (IMAGE f s) ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=> open_in (subtopology euclidean (IMAGE f s)) u))`,
REPEAT GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_RIGHT_INVERSE_IMP_QUOTIENT_MAP THEN EXISTS_TAC `g:real^N->real^M` THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
let QUOTIENT_MAP_OPEN_CLOSED = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> ((!u. u SUBSET t ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=> open_in (subtopology euclidean t) u)) <=> (!u. u SUBSET t ==> (closed_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=> closed_in (subtopology euclidean t) u)))`,
SIMP_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `u:real^N->bool` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `t DIFF u:real^N->bool`) THEN ASM_SIMP_TAC[SET_RULE `u SUBSET t ==> t DIFF (t DIFF u) = u`] THEN (ANTS_TAC THENL [SET_TAC[]; DISCH_THEN(SUBST1_TAC o SYM)]) THEN REWRITE_TAC[SUBSET_RESTRICT] THEN AP_TERM_TAC THEN ASM SET_TAC[]);;
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 LIFT_TO_QUOTIENT_SPACE = 
prove (`!f:real^M->real^N h:real^M->real^P s t u. IMAGE f s = t /\ (!v. v SUBSET t ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN v} <=> open_in (subtopology euclidean t) v)) /\ h continuous_on s /\ IMAGE h s = u /\ (!x y. x IN s /\ y IN s /\ f x = f y ==> h x = h y) ==> ?g. g continuous_on t /\ IMAGE g t = u /\ !x. x IN s ==> h(x) = g(f x)`,
REPEAT GEN_TAC THEN REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN REWRITE_TAC[FUNCTION_FACTORS_LEFT_GEN] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^P` THEN DISCH_TAC THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE_QUOTIENT THEN MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `s:real^M->bool`; `u:real^P->bool`] THEN ASM_SIMP_TAC[SUBSET_REFL] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] CONTINUOUS_ON_EQ)) THEN ASM_REWRITE_TAC[o_THM]);;
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 QUOTIENT_MAP_FROM_COMPOSITION = 
prove (`!f:real^M->real^N g:real^N->real^P s t u. f continuous_on s /\ IMAGE f s SUBSET t /\ g continuous_on t /\ IMAGE g t SUBSET u /\ (!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)) ==> !v. v SUBSET u ==> (open_in (subtopology euclidean t) {x | x IN t /\ g x IN v} <=> open_in (subtopology euclidean u) v)`,
REPEAT STRIP_TAC THEN EQ_TAC THEN STRIP_TAC THENL [FIRST_X_ASSUM(MP_TAC o SPEC `v:real^P->bool`) THEN ASM_REWRITE_TAC[o_THM] THEN DISCH_THEN(SUBST1_TAC o SYM) 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[]; ALL_TAC] THEN MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[]; MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN EXISTS_TAC `u:real^P->bool` THEN ASM_REWRITE_TAC[]]);;
let QUOTIENT_MAP_FROM_SUBSET = 
prove (`!f:real^M->real^N s t u. f continuous_on t /\ IMAGE f t SUBSET u /\ s SUBSET t /\ IMAGE f s = u /\ (!v. v SUBSET u ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN v} <=> open_in (subtopology euclidean u) v)) ==> !v. v SUBSET u ==> (open_in (subtopology euclidean t) {x | x IN t /\ f x IN v} <=> open_in (subtopology euclidean u) v)`,
REPEAT GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC QUOTIENT_MAP_FROM_COMPOSITION THEN MAP_EVERY EXISTS_TAC [`\x:real^M. x`; `s:real^M->bool`] THEN ASM_REWRITE_TAC[CONTINUOUS_ON_ID; IMAGE_ID; o_THM]);;
let QUOTIENT_MAP_RESTRICT = 
prove (`!f:real^M->real^N s t c. IMAGE f s SUBSET t /\ (!u. u SUBSET t ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=> open_in (subtopology euclidean t) u)) /\ (open_in (subtopology euclidean t) c \/ closed_in (subtopology euclidean t) c) ==> !u. u SUBSET c ==> (open_in (subtopology euclidean {x | x IN s /\ f x IN c}) {x | x IN {x | x IN s /\ f x IN c} /\ f x IN u} <=> open_in (subtopology euclidean c) u)`,
REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN DISCH_THEN(fun th -> MP_TAC th THEN MP_TAC (MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] QUOTIENT_MAP_IMP_CONTINUOUS_OPEN) th)) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN SUBGOAL_THEN `IMAGE (f:real^M->real^N) {x | x IN s /\ f x IN c} SUBSET c` ASSUME_TAC THENL [SET_TAC[]; ALL_TAC] THEN FIRST_X_ASSUM DISJ_CASES_TAC THENL [FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET); ASM_SIMP_TAC[QUOTIENT_MAP_OPEN_CLOSED] THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET)] THEN MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `u:real^N->bool` THEN DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN (ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN (MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THENL [MATCH_MP_TAC(MESON[] `t = s /\ (P s <=> Q s) ==> (P s <=> Q t)`) THEN CONJ_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_ELIM_THM]]; ALL_TAC]) THEN (EQ_TAC THENL [MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] OPEN_IN_SUBSET_TRANS) ORELSE MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] CLOSED_IN_SUBSET_TRANS); MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] OPEN_IN_TRANS) ORELSE MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] CLOSED_IN_TRANS)]) THEN (MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN ORELSE MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE_GEN ORELSE ASM_SIMP_TAC[]) THEN ASM SET_TAC[]);;
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[]);;
let CONNECTED_MONOTONE_QUOTIENT_PREIMAGE_GEN = 
prove (`!f:real^M->real^N s t c. 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}) /\ (open_in (subtopology euclidean t) c \/ closed_in (subtopology euclidean t) c) /\ connected c ==> connected {x | x IN s /\ f x IN c}`,
REPEAT GEN_TAC THEN REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ] (REWRITE_RULE[CONJ_ASSOC] CONNECTED_MONOTONE_QUOTIENT_PREIMAGE)) THEN SUBGOAL_THEN `(c:real^N->bool) SUBSET t` ASSUME_TAC THENL [ASM_MESON_TAC[OPEN_IN_IMP_SUBSET; CLOSED_IN_IMP_SUBSET]; ALL_TAC] THEN EXISTS_TAC `f:real^M->real^N` THEN REPEAT CONJ_TAC THENL [FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] QUOTIENT_MAP_IMP_CONTINUOUS_OPEN)) THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] CONTINUOUS_ON_SUBSET) THEN REWRITE_TAC[SUBSET_RESTRICT]; ASM SET_TAC[]; MATCH_MP_TAC QUOTIENT_MAP_RESTRICT THEN ASM_MESON_TAC[SUBSET_REFL]; X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`) THEN ANTS_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC EQ_IMP] THEN AP_TERM_TAC THEN ASM SET_TAC[]]);;
(* ------------------------------------------------------------------------- *) (* More properties of open and closed maps. *) (* ------------------------------------------------------------------------- *)
let OPEN_MAP_RESTRICT = 
prove (`!f:real^M->real^N s t t'. (!u. open_in (subtopology euclidean s) u ==> open_in (subtopology euclidean t) (IMAGE f u)) /\ t' SUBSET t ==> !u. open_in (subtopology euclidean {x | x IN s /\ f x IN t'}) u ==> open_in (subtopology euclidean t') (IMAGE f u)`,
REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_OPEN] THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM; IMP_CONJ] THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM; FORALL_UNWIND_THM2] THEN REPEAT DISCH_TAC THEN X_GEN_TAC `c:real^M->bool` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `c:real^M->bool`) THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[]);;
let CLOSED_MAP_RESTRICT = 
prove (`!f:real^M->real^N s t t'. (!u. closed_in (subtopology euclidean s) u ==> closed_in (subtopology euclidean t) (IMAGE f u)) /\ t' SUBSET t ==> !u. closed_in (subtopology euclidean {x | x IN s /\ f x IN t'}) u ==> closed_in (subtopology euclidean t') (IMAGE f u)`,
REPEAT GEN_TAC THEN REWRITE_TAC[CLOSED_IN_CLOSED] THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM; IMP_CONJ] THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM; FORALL_UNWIND_THM2] THEN REPEAT DISCH_TAC THEN X_GEN_TAC `c:real^M->bool` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `c:real^M->bool`) THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[]);;
let QUOTIENT_MAP_OPEN_MAP_EQ = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t /\ (!u. u SUBSET t ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=> open_in (subtopology euclidean t) u)) ==> ((!k. open_in (subtopology euclidean s) k ==> open_in (subtopology euclidean t) (IMAGE f k)) <=> (!k. open_in (subtopology euclidean s) k ==> open_in (subtopology euclidean s) {x | x IN s /\ f x IN IMAGE f k}))`,
REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `k:real^M->bool` THEN STRIP_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (f:real^M->real^N) k`) THEN ASM_SIMP_TAC[IMAGE_SUBSET] THEN DISCH_THEN MATCH_MP_TAC THEN ASM SET_TAC[]);;
let QUOTIENT_MAP_CLOSED_MAP_EQ = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t /\ (!u. u SUBSET t ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=> open_in (subtopology euclidean t) u)) ==> ((!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean t) (IMAGE f k)) <=> (!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean s) {x | x IN s /\ f x IN IMAGE f k}))`,
REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_SIMP_TAC[QUOTIENT_MAP_OPEN_CLOSED] THEN REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `k:real^M->bool` THEN STRIP_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (f:real^M->real^N) k`) THEN ASM_SIMP_TAC[IMAGE_SUBSET] THEN DISCH_THEN MATCH_MP_TAC THEN ASM SET_TAC[]);;
let CLOSED_MAP_IMP_OPEN_MAP = 
prove (`!f:real^M->real^N s t. IMAGE f s = t /\ (!u. closed_in (subtopology euclidean s) u ==> closed_in (subtopology euclidean t) (IMAGE f u)) /\ (!u. open_in (subtopology euclidean s) u ==> open_in (subtopology euclidean s) {x | x IN s /\ f x IN IMAGE f u}) ==> (!u. open_in (subtopology euclidean s) u ==> open_in (subtopology euclidean t) (IMAGE f u))`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `IMAGE (f:real^M->real^N) u = t DIFF IMAGE f (s DIFF {x | x IN s /\ f x IN IMAGE f u})` SUBST1_TAC THENL [FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN ASM SET_TAC[]; MATCH_MP_TAC OPEN_IN_DIFF THEN REWRITE_TAC[OPEN_IN_REFL] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN MATCH_MP_TAC CLOSED_IN_DIFF THEN REWRITE_TAC[OPEN_IN_REFL] THEN ASM_SIMP_TAC[CLOSED_IN_REFL]]);;
let OPEN_MAP_IMP_CLOSED_MAP = 
prove (`!f:real^M->real^N s t. IMAGE f s = t /\ (!u. open_in (subtopology euclidean s) u ==> open_in (subtopology euclidean t) (IMAGE f u)) /\ (!u. closed_in (subtopology euclidean s) u ==> closed_in (subtopology euclidean s) {x | x IN s /\ f x IN IMAGE f u}) ==> (!u. closed_in (subtopology euclidean s) u ==> closed_in (subtopology euclidean t) (IMAGE f u))`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `IMAGE (f:real^M->real^N) u = t DIFF IMAGE f (s DIFF {x | x IN s /\ f x IN IMAGE f u})` SUBST1_TAC THENL [FIRST_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN ASM SET_TAC[]; MATCH_MP_TAC CLOSED_IN_DIFF THEN REWRITE_TAC[CLOSED_IN_REFL] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN MATCH_MP_TAC OPEN_IN_DIFF THEN REWRITE_TAC[CLOSED_IN_REFL] THEN ASM_SIMP_TAC[OPEN_IN_REFL]]);;
let OPEN_MAP_FROM_COMPOSITION_SURJECTIVE = 
prove (`!f:real^M->real^N g:real^N->real^P s t u. f continuous_on s /\ IMAGE f s = t /\ IMAGE g t SUBSET u /\ (!k. open_in (subtopology euclidean s) k ==> open_in (subtopology euclidean u) (IMAGE (g o f) k)) ==> (!k. open_in (subtopology euclidean t) k ==> open_in (subtopology euclidean u) (IMAGE g k))`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `IMAGE g k = IMAGE ((g:real^N->real^P) o (f:real^M->real^N)) {x | x IN s /\ f(x) IN k}` SUBST1_TAC THENL [FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[]; FIRST_X_ASSUM MATCH_MP_TAC THEN MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[SUBSET_REFL]]);;
let CLOSED_MAP_FROM_COMPOSITION_SURJECTIVE = 
prove (`!f:real^M->real^N g:real^N->real^P s t u. f continuous_on s /\ IMAGE f s = t /\ IMAGE g t SUBSET u /\ (!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean u) (IMAGE (g o f) k)) ==> (!k. closed_in (subtopology euclidean t) k ==> closed_in (subtopology euclidean u) (IMAGE g k))`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `IMAGE g k = IMAGE ((g:real^N->real^P) o (f:real^M->real^N)) {x | x IN s /\ f(x) IN k}` SUBST1_TAC THENL [FIRST_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[]; FIRST_X_ASSUM MATCH_MP_TAC THEN MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE_GEN THEN EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[SUBSET_REFL]]);;
let OPEN_MAP_FROM_COMPOSITION_INJECTIVE = 
prove (`!f:real^M->real^N g:real^N->real^P s t u. IMAGE f s SUBSET t /\ IMAGE g t SUBSET u /\ g continuous_on t /\ (!x y. x IN t /\ y IN t /\ g x = g y ==> x = y) /\ (!k. open_in (subtopology euclidean s) k ==> open_in (subtopology euclidean u) (IMAGE (g o f) k)) ==> (!k. open_in (subtopology euclidean s) k ==> open_in (subtopology euclidean t) (IMAGE f k))`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `IMAGE f k = {x | x IN t /\ g(x) IN IMAGE ((g:real^N->real^P) o (f:real^M->real^N)) k}` SUBST1_TAC THENL [FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[]; MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN EXISTS_TAC `u:real^P->bool` THEN ASM_SIMP_TAC[]]);;
let CLOSED_MAP_FROM_COMPOSITION_INJECTIVE = 
prove (`!f:real^M->real^N g:real^N->real^P s t u. IMAGE f s SUBSET t /\ IMAGE g t SUBSET u /\ g continuous_on t /\ (!x y. x IN t /\ y IN t /\ g x = g y ==> x = y) /\ (!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean u) (IMAGE (g o f) k)) ==> (!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean t) (IMAGE f k))`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `IMAGE f k = {x | x IN t /\ g(x) IN IMAGE ((g:real^N->real^P) o (f:real^M->real^N)) k}` SUBST1_TAC THENL [FIRST_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[]; MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE_GEN THEN EXISTS_TAC `u:real^P->bool` THEN ASM_SIMP_TAC[]]);;
let OPEN_MAP_CLOSED_SUPERSET_PREIMAGE = 
prove (`!f:real^M->real^N s t u w. (!k. open_in (subtopology euclidean s) k ==> open_in (subtopology euclidean t) (IMAGE f k)) /\ closed_in (subtopology euclidean s) u /\ w SUBSET t /\ {x | x IN s /\ f(x) IN w} SUBSET u ==> ?v. closed_in (subtopology euclidean t) v /\ w SUBSET v /\ {x | x IN s /\ f(x) IN v} SUBSET u`,
REPEAT STRIP_TAC THEN EXISTS_TAC `t DIFF IMAGE (f:real^M->real^N) (s DIFF u)` THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN MATCH_MP_TAC CLOSED_IN_DIFF THEN REWRITE_TAC[CLOSED_IN_REFL] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[OPEN_IN_DIFF; OPEN_IN_REFL]);;
let OPEN_MAP_CLOSED_SUPERSET_PREIMAGE_EQ = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> ((!k. open_in (subtopology euclidean s) k ==> open_in (subtopology euclidean t) (IMAGE f k)) <=> (!u w. closed_in (subtopology euclidean s) u /\ w SUBSET t /\ {x | x IN s /\ f(x) IN w} SUBSET u ==> ?v. closed_in (subtopology euclidean t) v /\ w SUBSET v /\ {x | x IN s /\ f(x) IN v} SUBSET u))`,
REPEAT(STRIP_TAC ORELSE EQ_TAC) THEN ASM_SIMP_TAC[OPEN_MAP_CLOSED_SUPERSET_PREIMAGE] THEN FIRST_X_ASSUM(MP_TAC o SPECL [`s DIFF k:real^M->bool`; `t DIFF IMAGE (f:real^M->real^N) k`]) THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN ASM_SIMP_TAC[CLOSED_IN_DIFF; CLOSED_IN_REFL] THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` STRIP_ASSUME_TAC) THEN SUBGOAL_THEN `IMAGE (f:real^M->real^N) k = t DIFF v` SUBST1_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[OPEN_IN_DIFF; OPEN_IN_REFL]]);;
let CLOSED_MAP_OPEN_SUPERSET_PREIMAGE = 
prove (`!f:real^M->real^N s t u w. (!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean t) (IMAGE f k)) /\ open_in (subtopology euclidean s) u /\ w SUBSET t /\ {x | x IN s /\ f(x) IN w} SUBSET u ==> ?v. open_in (subtopology euclidean t) v /\ w SUBSET v /\ {x | x IN s /\ f(x) IN v} SUBSET u`,
REPEAT STRIP_TAC THEN EXISTS_TAC `t DIFF IMAGE (f:real^M->real^N) (s DIFF u)` THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN MATCH_MP_TAC OPEN_IN_DIFF THEN REWRITE_TAC[OPEN_IN_REFL] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[CLOSED_IN_DIFF; CLOSED_IN_REFL]);;
let CLOSED_MAP_OPEN_SUPERSET_PREIMAGE_EQ = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> ((!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean t) (IMAGE f k)) <=> (!u w. open_in (subtopology euclidean s) u /\ w SUBSET t /\ {x | x IN s /\ f(x) IN w} SUBSET u ==> ?v. open_in (subtopology euclidean t) v /\ w SUBSET v /\ {x | x IN s /\ f(x) IN v} SUBSET u))`,
REPEAT(STRIP_TAC ORELSE EQ_TAC) THEN ASM_SIMP_TAC[CLOSED_MAP_OPEN_SUPERSET_PREIMAGE] THEN FIRST_X_ASSUM(MP_TAC o SPECL [`s DIFF k:real^M->bool`; `t DIFF IMAGE (f:real^M->real^N) k`]) THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN ASM_SIMP_TAC[OPEN_IN_DIFF; OPEN_IN_REFL] THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` STRIP_ASSUME_TAC) THEN SUBGOAL_THEN `IMAGE (f:real^M->real^N) k = t DIFF v` SUBST1_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[CLOSED_IN_DIFF; CLOSED_IN_REFL]]);;
let CLOSED_MAP_OPEN_SUPERSET_PREIMAGE_POINT = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> ((!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean t) (IMAGE f k)) <=> (!u y. open_in (subtopology euclidean s) u /\ y IN t /\ {x | x IN s /\ f(x) = y} SUBSET u ==> ?v. open_in (subtopology euclidean t) v /\ y IN v /\ {x | x IN s /\ f(x) IN v} SUBSET u))`,
REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CLOSED_MAP_OPEN_SUPERSET_PREIMAGE_EQ] THEN EQ_TAC THEN DISCH_TAC THENL [MAP_EVERY X_GEN_TAC [`u:real^M->bool`; `y:real^N`] THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^M->bool`; `{y:real^N}`]) THEN ASM_REWRITE_TAC[SING_SUBSET; IN_SING]; MAP_EVERY X_GEN_TAC [`u:real^M->bool`; `w:real^N->bool`] THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `u:real^M->bool`) 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 `vv:real^N->real^N->bool` THEN DISCH_TAC THEN EXISTS_TAC `UNIONS {(vv:real^N->real^N->bool) y | y IN w}` THEN CONJ_TAC THENL [MATCH_MP_TAC OPEN_IN_UNIONS THEN REWRITE_TAC[FORALL_IN_GSPEC] THEN ASM SET_TAC[]; REWRITE_TAC[UNIONS_GSPEC] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN REWRITE_TAC[SUBSET; IN_ELIM_THM; RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^N`] THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`) THEN ASM SET_TAC[]]]);;
let CONNECTED_OPEN_MONOTONE_PREIMAGE = 
prove (`!f:real^M->real^N s t. f continuous_on s /\ IMAGE f s = t /\ (!c. open_in (subtopology euclidean s) c ==> open_in (subtopology euclidean t) (IMAGE f c)) /\ (!y. y IN t ==> connected {x | x IN s /\ f x = y}) ==> !c. connected c /\ c SUBSET t ==> connected {x | x IN s /\ f x IN c}`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o SPEC `c:real^N->bool` o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ] OPEN_MAP_RESTRICT)) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN MP_TAC(ISPECL [`f:real^M->real^N`; `{x | x IN s /\ (f:real^M->real^N) x IN c}`] OPEN_MAP_IMP_QUOTIENT_MAP) THEN SUBGOAL_THEN `IMAGE f {x | x IN s /\ (f:real^M->real^N) x IN c} = c` ASSUME_TAC THENL [ASM SET_TAC[]; ASM_REWRITE_TAC[]] THEN ANTS_TAC THENL [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_SUBSET)) THEN SET_TAC[]; DISCH_TAC] THEN MATCH_MP_TAC CONNECTED_MONOTONE_QUOTIENT_PREIMAGE THEN MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `c:real^N->bool`] THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_SUBSET)) THEN SET_TAC[]; SIMP_TAC[SET_RULE `y IN c ==> {x | x IN {x | x IN s /\ f x IN c} /\ f x = y} = {x | x IN s /\ f x = y}`] THEN ASM SET_TAC[]]);;
let CONNECTED_CLOSED_MONOTONE_PREIMAGE = 
prove (`!f:real^M->real^N s t. f continuous_on s /\ IMAGE f s = t /\ (!c. closed_in (subtopology euclidean s) c ==> closed_in (subtopology euclidean t) (IMAGE f c)) /\ (!y. y IN t ==> connected {x | x IN s /\ f x = y}) ==> !c. connected c /\ c SUBSET t ==> connected {x | x IN s /\ f x IN c}`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o SPEC `c:real^N->bool` o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ] CLOSED_MAP_RESTRICT)) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN MP_TAC(ISPECL [`f:real^M->real^N`; `{x | x IN s /\ (f:real^M->real^N) x IN c}`] CLOSED_MAP_IMP_QUOTIENT_MAP) THEN SUBGOAL_THEN `IMAGE f {x | x IN s /\ (f:real^M->real^N) x IN c} = c` ASSUME_TAC THENL [ASM SET_TAC[]; ASM_REWRITE_TAC[]] THEN ANTS_TAC THENL [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_SUBSET)) THEN SET_TAC[]; DISCH_TAC] THEN MATCH_MP_TAC CONNECTED_MONOTONE_QUOTIENT_PREIMAGE THEN MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `c:real^N->bool`] THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_SUBSET)) THEN SET_TAC[]; SIMP_TAC[SET_RULE `y IN c ==> {x | x IN {x | x IN s /\ f x IN c} /\ f x = y} = {x | x IN s /\ f x = y}`] THEN ASM SET_TAC[]]);;
(* ------------------------------------------------------------------------- *) (* Proper maps, including projections out of compact sets. *) (* ------------------------------------------------------------------------- *)
let PROPER_MAP = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> ((!k. k SUBSET t /\ compact k ==> compact {x | x IN s /\ f x IN k}) <=> (!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean t) (IMAGE f k)) /\ (!a. a IN t ==> compact {x | x IN s /\ f x = a}))`,
REPEAT STRIP_TAC THEN EQ_TAC THENL [REPEAT STRIP_TAC THENL [ALL_TAC; ONCE_REWRITE_TAC[SET_RULE `x = a <=> x IN {a}`] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[SING_SUBSET; COMPACT_SING]] THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN REWRITE_TAC[CLOSED_IN_LIMPT] THEN CONJ_TAC THENL [ASM SET_TAC[]; X_GEN_TAC `y:real^N`] THEN REWRITE_TAC[LIMPT_SEQUENTIAL_INJ; IN_DELETE] THEN REWRITE_TAC[IN_IMAGE; LEFT_AND_EXISTS_THM; SKOLEM_THM] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[GSYM CONJ_ASSOC; FORALL_AND_THM] THEN ONCE_REWRITE_TAC[GSYM FUN_EQ_THM] THEN REWRITE_TAC[UNWIND_THM2; FUN_EQ_THM] THEN DISCH_THEN(X_CHOOSE_THEN `x:num->real^M` STRIP_ASSUME_TAC) THEN SUBGOAL_THEN `~(INTERS {{a | a IN k /\ (f:real^M->real^N) a IN (y INSERT IMAGE (\i. f(x(n + i))) (:num))} | n IN (:num)} = {})` MP_TAC THENL [MATCH_MP_TAC COMPACT_FIP THEN CONJ_TAC THENL [REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV] THEN X_GEN_TAC `n:num` THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CLOSED_IN_CLOSED]) THEN DISCH_THEN(X_CHOOSE_THEN `c:real^M->bool` STRIP_ASSUME_TAC) THEN ASM_REWRITE_TAC[SET_RULE `{x | x IN s INTER k /\ P x} = k INTER {x | x IN s /\ P x}`] THEN MATCH_MP_TAC CLOSED_INTER_COMPACT THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN MATCH_MP_TAC COMPACT_SEQUENCE_WITH_LIMIT THEN FIRST_ASSUM(MP_TAC o SPEC `n:num` o MATCH_MP SEQ_OFFSET) THEN REWRITE_TAC[ADD_SYM]; REWRITE_TAC[SIMPLE_IMAGE; FORALL_FINITE_SUBSET_IMAGE] THEN X_GEN_TAC `i:num->bool` THEN STRIP_TAC THEN FIRST_ASSUM(MP_TAC o ISPEC `\n:num. n` o MATCH_MP UPPER_BOUND_FINITE_SET) THEN REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_TAC `m:num`) THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; INTERS_IMAGE; IN_ELIM_THM] THEN EXISTS_TAC `(x:num->real^M) m` THEN X_GEN_TAC `p:num` THEN DISCH_TAC THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN REWRITE_TAC[IN_INSERT; IN_IMAGE; IN_UNIV] THEN DISJ2_TAC THEN EXISTS_TAC `m - p:num` THEN ASM_MESON_TAC[ARITH_RULE `p <= m ==> p + m - p:num = m`]]; REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real^M` THEN REWRITE_TAC[INTERS_GSPEC; IN_ELIM_THM; IN_UNIV] THEN DISCH_THEN(fun th -> LABEL_TAC "*" th THEN MP_TAC(SPEC `0` th)) THEN REWRITE_TAC[ADD_CLAUSES; IN_INSERT; IN_IMAGE; IN_UNIV] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (DISJ_CASES_THEN MP_TAC)) THEN ASM_SIMP_TAC[] THEN DISCH_THEN(X_CHOOSE_TAC `i:num`) THEN REMOVE_THEN "*" (MP_TAC o SPEC `i + 1`) THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN ASM_REWRITE_TAC[IN_INSERT; IN_IMAGE; IN_UNIV] THEN ARITH_TAC]; STRIP_TAC THEN X_GEN_TAC `k:real^N->bool` THEN STRIP_TAC THEN REWRITE_TAC[COMPACT_EQ_HEINE_BOREL] THEN X_GEN_TAC `c:(real^M->bool)->bool` THEN STRIP_TAC THEN SUBGOAL_THEN `!a. a IN k ==> ?g. g SUBSET c /\ FINITE g /\ {x | x IN s /\ (f:real^M->real^N) x = a} SUBSET UNIONS g` MP_TAC THENL [X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN UNDISCH_THEN `!a. a IN t ==> compact {x | x IN s /\ (f:real^M->real^N) x = a}` (MP_TAC o SPEC `a:real^N`) THEN ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[COMPACT_EQ_HEINE_BOREL]] THEN DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[]; 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->(real^M->bool)->bool` THEN DISCH_THEN(LABEL_TAC "*")] THEN SUBGOAL_THEN `!a. a IN k ==> ?v. open v /\ a IN v /\ {x | x IN s /\ (f:real^M->real^N) x IN v} SUBSET UNIONS(uu a)` MP_TAC THENL [REPEAT STRIP_TAC THEN UNDISCH_THEN `!k. closed_in (subtopology euclidean s) k ==> closed_in (subtopology euclidean t) (IMAGE (f:real^M->real^N) k)` (MP_TAC o SPEC `(s:real^M->bool) DIFF UNIONS(uu(a:real^N))`) THEN SIMP_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN ANTS_TAC THENL [CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN REWRITE_TAC[SET_RULE `s DIFF (s DIFF t) = s INTER t`] THEN MATCH_MP_TAC OPEN_IN_OPEN_INTER THEN MATCH_MP_TAC OPEN_UNIONS THEN ASM SET_TAC[]; DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN REWRITE_TAC[OPEN_IN_OPEN] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `v:real^N->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `a:real^N`)) THEN ASM_REWRITE_TAC[] THEN REPEAT ((ANTS_TAC THENL [ASM SET_TAC[]; DISCH_TAC]) ORELSE STRIP_TAC) THENL [ALL_TAC; ASM SET_TAC[]] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN DISCH_THEN(MP_TAC o SPEC `a:real^N`) THEN ASM SET_TAC[]]; 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 `vv:real^N->(real^N->bool)` THEN DISCH_THEN(LABEL_TAC "+")] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [COMPACT_EQ_HEINE_BOREL]) THEN DISCH_THEN(MP_TAC o SPEC `IMAGE (vv:real^N->(real^N->bool)) k`) THEN ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN ONCE_REWRITE_TAC[TAUT `p /\ q /\ r ==> s <=> q /\ p ==> r ==> s`] THEN REWRITE_TAC[FORALL_FINITE_SUBSET_IMAGE] THEN X_GEN_TAC `j:real^N->bool` THEN REPEAT STRIP_TAC THEN EXISTS_TAC `UNIONS(IMAGE (uu:real^N->(real^M->bool)->bool) j)` THEN REPEAT CONJ_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[FINITE_UNIONS; FORALL_IN_IMAGE; FINITE_IMAGE] THEN ASM SET_TAC[]; REWRITE_TAC[UNIONS_IMAGE; SUBSET; IN_UNIONS; IN_ELIM_THM] THEN ASM SET_TAC[]]]);;
let COMPACT_CONTINUOUS_IMAGE_EQ = 
prove (`!f:real^M->real^N s. (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) ==> (f continuous_on s <=> !t. compact t /\ t SUBSET s ==> compact(IMAGE f t))`,
REPEAT STRIP_TAC THEN EQ_TAC THENL [MESON_TAC[COMPACT_CONTINUOUS_IMAGE; CONTINUOUS_ON_SUBSET]; DISCH_TAC] THEN FIRST_X_ASSUM(X_CHOOSE_TAC `g:real^N->real^M` o GEN_REWRITE_RULE I [INJECTIVE_ON_LEFT_INVERSE]) THEN REWRITE_TAC[CONTINUOUS_ON_CLOSED] THEN X_GEN_TAC `u:real^N->bool` THEN DISCH_TAC THEN MP_TAC(ISPECL [`g:real^N->real^M`; `IMAGE (f:real^M->real^N) s`; `s:real^M->bool`] PROPER_MAP) THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN MATCH_MP_TAC(TAUT `(q ==> s) /\ p ==> (p <=> q /\ r) ==> s`) THEN REPEAT STRIP_TAC THENL [SUBGOAL_THEN `{x | x IN s /\ (f:real^M->real^N) x IN u} = IMAGE g u` (fun th -> ASM_MESON_TAC[th]); SUBGOAL_THEN `{x | x IN IMAGE f s /\ (g:real^N->real^M) x IN k} = IMAGE f k` (fun th -> ASM_SIMP_TAC[th])] THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN ASM SET_TAC[]);;
let PROPER_MAP_FROM_COMPACT = 
prove (`!f:real^M->real^N s k. f continuous_on s /\ IMAGE f s SUBSET t /\ compact s /\ closed_in (subtopology euclidean t) k ==> compact {x | x IN s /\ f x IN k}`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSED_IN_COMPACT THEN EXISTS_TAC `s:real^M->bool` THEN ASM_MESON_TAC[CONTINUOUS_CLOSED_IN_PREIMAGE_GEN]);;
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[]);;
let PROPER_MAP_FROM_COMPOSITION_LEFT = 
prove (`!f:real^M->real^N g:real^N->real^P s t u. f continuous_on s /\ IMAGE f s = t /\ g continuous_on t /\ IMAGE g t SUBSET u /\ (!k. k SUBSET u /\ compact k ==> compact {x | x IN s /\ (g o f) x IN k}) ==> !k. k SUBSET u /\ compact k ==> compact {x | x IN t /\ g x IN k}`,
REWRITE_TAC[o_THM] THEN REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `k:real^P->bool`) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o ISPEC `f:real^M->real^N` o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] COMPACT_CONTINUOUS_IMAGE)) THEN ANTS_TAC THENL [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_SUBSET)) THEN SET_TAC[]; MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]]);;
let PROPER_MAP_FROM_COMPOSITION_RIGHT = 
prove (`!f:real^M->real^N g:real^N->real^P s t u. f continuous_on s /\ IMAGE f s SUBSET t /\ g continuous_on t /\ IMAGE g t SUBSET u /\ (!k. k SUBSET u /\ compact k ==> compact {x | x IN s /\ (g o f) x IN k}) ==> !k. k SUBSET t /\ compact k ==> compact {x | x IN s /\ f x IN k}`,
let lemma = prove
   (`!s t. closed_in (subtopology euclidean s) t ==> compact s ==> compact t`,
    MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_SUBSET;
              CLOSED_IN_CLOSED_EQ]) in
  REWRITE_TAC[o_THM] THEN REPEAT STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (g:real^N->real^P) k`) THEN
  ANTS_TAC THENL
   [CONJ_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE] THEN
    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
    MATCH_MP_TAC lemma THEN
    MATCH_MP_TAC CLOSED_IN_SUBSET_TRANS THEN
    EXISTS_TAC `s:real^M->bool` THEN
    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
    MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE_GEN THEN
    EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
    MATCH_MP_TAC CLOSED_SUBSET THEN ASM_SIMP_TAC[COMPACT_IMP_CLOSED]]);;
let PROPER_MAP_FSTCART = 
prove (`!s:real^M->bool t:real^N->bool k. compact t /\ k SUBSET s /\ compact k ==> compact {z | z IN s PCROSS t /\ fstcart z IN k}`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `{z | z IN s PCROSS t /\ fstcart z IN k} = (k:real^M->bool) PCROSS (t:real^N->bool)` (fun th -> ASM_SIMP_TAC[th; COMPACT_PCROSS]) THEN REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_ELIM_THM; PASTECART_IN_PCROSS; FSTCART_PASTECART] THEN ASM SET_TAC[]);;
let CLOSED_MAP_FSTCART = 
prove (`!s:real^M->bool t:real^N->bool c. compact t /\ closed_in (subtopology euclidean (s PCROSS t)) c ==> closed_in (subtopology euclidean s) (IMAGE fstcart c)`,
REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`; `(s:real^M->bool) PCROSS (t:real^N->bool)`; `s:real^M->bool`] PROPER_MAP) THEN ASM_SIMP_TAC[PROPER_MAP_FSTCART; IMAGE_FSTCART_PCROSS] THEN ASM SET_TAC[]);;
let PROPER_MAP_SNDCART = 
prove (`!s:real^M->bool t:real^N->bool k. compact s /\ k SUBSET t /\ compact k ==> compact {z | z IN s PCROSS t /\ sndcart z IN k}`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `{z | z IN s PCROSS t /\ sndcart z IN k} = (s:real^M->bool) PCROSS (k:real^N->bool)` (fun th -> ASM_SIMP_TAC[th; COMPACT_PCROSS]) THEN REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_ELIM_THM; PASTECART_IN_PCROSS; SNDCART_PASTECART] THEN ASM SET_TAC[]);;
let CLOSED_MAP_SNDCART = 
prove (`!s:real^M->bool t:real^N->bool c. compact s /\ closed_in (subtopology euclidean (s PCROSS t)) c ==> closed_in (subtopology euclidean t) (IMAGE sndcart c)`,
REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`; `(s:real^M->bool) PCROSS (t:real^N->bool)`; `t:real^N->bool`] PROPER_MAP) THEN ASM_SIMP_TAC[PROPER_MAP_SNDCART; IMAGE_SNDCART_PCROSS] THEN ASM SET_TAC[]);;
let CLOSED_IN_COMPACT_PROJECTION = 
prove (`!s:real^M->bool t:real^N->bool u. compact s /\ closed_in (subtopology euclidean (s PCROSS t)) u ==> closed_in (subtopology euclidean t) {y | ?x. x IN s /\ pastecart x y IN u}`,
REPEAT GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP CLOSED_MAP_SNDCART) THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET o CONJUNCT2) THEN REWRITE_TAC[EXTENSION; SUBSET; IN_IMAGE; FORALL_PASTECART; EXISTS_PASTECART; PASTECART_IN_PCROSS; IN_ELIM_THM; SNDCART_PASTECART] THEN SET_TAC[]);;
let CLOSED_COMPACT_PROJECTION = 
prove (`!s:real^M->bool t:real^(M,N)finite_sum->bool. compact s /\ closed t ==> closed {y | ?x. x IN s /\ pastecart x y IN t}`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `{y | ?x:real^M. x IN s /\ pastecart x y IN t} = {y | ?x. x IN s /\ pastecart x y IN ((s PCROSS (:real^N)) INTER t)}` SUBST1_TAC THENL [REWRITE_TAC[PASTECART_IN_PCROSS; IN_UNIV; IN_INTER] THEN SET_TAC[]; MATCH_MP_TAC CLOSED_IN_CLOSED_TRANS THEN EXISTS_TAC `(:real^N)` THEN REWRITE_TAC[CLOSED_UNIV] THEN MATCH_MP_TAC CLOSED_IN_COMPACT_PROJECTION THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CLOSED_SUBSET THEN ASM_SIMP_TAC[CLOSED_INTER; CLOSED_UNIV; CLOSED_PCROSS; COMPACT_IMP_CLOSED; INTER_SUBSET]]);;
let TUBE_LEMMA = 
prove (`!s:real^M->bool t:real^N->bool u a. compact s /\ ~(s = {}) /\ {pastecart x a | x IN s} SUBSET u /\ open_in(subtopology euclidean (s PCROSS t)) u ==> ?v. open_in (subtopology euclidean t) v /\ a IN v /\ (s PCROSS v) SUBSET u`,
REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS] THEN REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ] THEN REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT; PCROSS] CLOSED_IN_COMPACT_PROJECTION)) THEN ASM_REWRITE_TAC[IN_ELIM_PASTECART_THM; IN_DIFF] THEN REWRITE_TAC[GSYM CONJ_ASSOC] THEN MATCH_MP_TAC(MESON[] `(closed_in top t ==> s DIFF (s DIFF t) = t) /\ s DIFF t SUBSET s /\ P(s DIFF t) ==> closed_in top t ==> ?v. v SUBSET s /\ closed_in top (s DIFF v) /\ P v`) THEN REWRITE_TAC[SET_RULE `s DIFF (s DIFF t) = t <=> t SUBSET s`] THEN REWRITE_TAC[SUBSET_DIFF] THEN SIMP_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN REWRITE_TAC[IN_DIFF; IN_ELIM_THM] THEN REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN CONJ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET])) THEN REWRITE_TAC[FORALL_IN_GSPEC; IN_SING; FORALL_PASTECART] THEN REWRITE_TAC[IN_ELIM_PASTECART_THM] THEN ASM_MESON_TAC[MEMBER_NOT_EMPTY]);;
let TUBE_LEMMA_GEN = 
prove (`!s t t' u:real^(M,N)finite_sum->bool. compact s /\ ~(s = {}) /\ t SUBSET t' /\ s PCROSS t SUBSET u /\ open_in (subtopology euclidean (s PCROSS t')) u ==> ?v. open_in (subtopology euclidean t') v /\ t SUBSET v /\ s PCROSS v SUBSET u`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `!a. a IN t ==> ?v. open_in (subtopology euclidean t') v /\ a IN v /\ (s:real^M->bool) PCROSS (v:real^N->bool) SUBSET u` MP_TAC THENL [REPEAT STRIP_TAC THEN MATCH_MP_TAC TUBE_LEMMA THEN ASM_REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN REPEAT STRIP_TAC THEN REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET]) THEN ASM_REWRITE_TAC[PASTECART_IN_PCROSS]; 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 `vv:real^N->real^N->bool` THEN DISCH_TAC THEN EXISTS_TAC `UNIONS (IMAGE (vv:real^N->real^N->bool) t)` THEN ASM_SIMP_TAC[OPEN_IN_UNIONS; FORALL_IN_IMAGE] THEN REWRITE_TAC[SUBSET; UNIONS_IMAGE; IN_ELIM_THM; FORALL_IN_PCROSS] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^N`] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_TAC `c:real^N`)) THEN FIRST_X_ASSUM(MP_TAC o SPEC `c:real^N`) THEN ASM_REWRITE_TAC[SUBSET; FORALL_IN_PCROSS] THEN ASM SET_TAC[]]);;
(* ------------------------------------------------------------------------- *) (* Pasting functions together on open sets. *) (* ------------------------------------------------------------------------- *)
let PASTING_LEMMA = 
prove (`!f:A->real^M->real^N g t s 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) /\ (!x. x IN s ==> ?j. j IN k /\ x IN t j /\ g x = f j x) ==> g continuous_on s`,
REPEAT GEN_TAC THEN REWRITE_TAC[CONTINUOUS_OPEN_IN_PREIMAGE_EQ] THEN STRIP_TAC THEN X_GEN_TAC `u:real^N->bool` THEN DISCH_TAC THEN SUBGOAL_THEN `{x | x IN s /\ g x IN u} = UNIONS {{x | x IN (t i) /\ ((f:A->real^M->real^N) i x) IN u} | i IN k}` SUBST1_TAC THENL [SUBGOAL_THEN `!i. i IN k ==> ((t:A->real^M->bool) i) SUBSET s` ASSUME_TAC THENL [ASM_MESON_TAC[OPEN_IN_SUBSET; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY]; REWRITE_TAC[UNIONS_GSPEC] THEN ASM SET_TAC[]]; MATCH_MP_TAC OPEN_IN_UNIONS THEN REWRITE_TAC[FORALL_IN_GSPEC] THEN ASM_MESON_TAC[OPEN_IN_TRANS]]);;
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[]);;
let CONTINUOUS_ON_UNION_LOCAL_OPEN = 
prove (`!f:real^M->real^N s. open_in (subtopology euclidean (s UNION t)) s /\ open_in (subtopology euclidean (s UNION t)) t /\ f continuous_on s /\ f continuous_on t ==> f continuous_on (s UNION t)`,
REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`\i:(real^M->bool). (f:real^M->real^N)`; `f:real^M->real^N`; `\i:(real^M->bool). i`; `s UNION t:real^M->bool`; `{s:real^M->bool,t}`] PASTING_LEMMA) THEN DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[FORALL_IN_INSERT; EXISTS_IN_INSERT; NOT_IN_EMPTY] THEN REWRITE_TAC[IN_UNION]);;
let CONTINUOUS_ON_UNION_OPEN = 
prove (`!f s t. open s /\ open t /\ f continuous_on s /\ f continuous_on t ==> f continuous_on (s UNION t)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_UNION_LOCAL_OPEN THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THEN MATCH_MP_TAC OPEN_OPEN_IN_TRANS THEN ASM_SIMP_TAC[OPEN_UNION] THEN SET_TAC[]);;
let CONTINUOUS_ON_CASES_LOCAL_OPEN = 
prove (`!P f g:real^M->real^N s t. open_in (subtopology euclidean (s UNION t)) s /\ open_in (subtopology euclidean (s UNION t)) t /\ f continuous_on s /\ g continuous_on t /\ (!x. x IN s /\ ~P x \/ x IN t /\ P x ==> f x = g x) ==> (\x. if P x then f x else g x) continuous_on (s UNION t)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_UNION_LOCAL_OPEN THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_EQ THENL [EXISTS_TAC `f:real^M->real^N`; EXISTS_TAC `g:real^M->real^N`] THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);;
let CONTINUOUS_ON_CASES_OPEN = 
prove (`!P f g s t. open s /\ open t /\ f continuous_on s /\ g continuous_on t /\ (!x. x IN s /\ ~P x \/ x IN t /\ P x ==> f x = g x) ==> (\x. if P x then f x else g x) continuous_on s UNION t`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL_OPEN THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THEN MATCH_MP_TAC OPEN_OPEN_IN_TRANS THEN ASM_SIMP_TAC[OPEN_UNION] THEN SET_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Likewise on closed sets, with a finiteness assumption. *) (* ------------------------------------------------------------------------- *)
let PASTING_LEMMA_CLOSED = 
prove (`!f:A->real^M->real^N g t s k. FINITE k /\ (!i. i IN k ==> closed_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) /\ (!x. x IN s ==> ?j. j IN k /\ x IN t j /\ g x = f j x) ==> g continuous_on s`,
REPEAT GEN_TAC THEN REWRITE_TAC[CONTINUOUS_CLOSED_IN_PREIMAGE_EQ] THEN STRIP_TAC THEN X_GEN_TAC `u:real^N->bool` THEN DISCH_TAC THEN SUBGOAL_THEN `{x | x IN s /\ g x IN u} = UNIONS {{x | x IN (t i) /\ ((f:A->real^M->real^N) i x) IN u} | i IN k}` SUBST1_TAC THENL [SUBGOAL_THEN `!i. i IN k ==> ((t:A->real^M->bool) i) SUBSET s` ASSUME_TAC THENL [ASM_MESON_TAC[CLOSED_IN_SUBSET; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY]; REWRITE_TAC[UNIONS_GSPEC] THEN ASM SET_TAC[]]; MATCH_MP_TAC CLOSED_IN_UNIONS THEN ASM_SIMP_TAC[SIMPLE_IMAGE; FINITE_IMAGE; FORALL_IN_IMAGE] THEN ASM_MESON_TAC[CLOSED_IN_TRANS]]);;
let PASTING_LEMMA_EXISTS_CLOSED = 
prove (`!f:A->real^M->real^N t s k. FINITE k /\ s SUBSET UNIONS {t i | i IN k} /\ (!i. i IN k ==> closed_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_CLOSED THEN MAP_EVERY EXISTS_TAC [`f:A->real^M->real^N`; `t:A->real^M->bool`; `k:A->bool`] THEN ASM SET_TAC[]);;
(* ------------------------------------------------------------------------- *) (* 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`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `a = vec 0:real^N` THENL [ASM_REWRITE_TAC[DOT_LZERO; LIFT_NUM; o_DEF; LIM_CONST]; ALL_TAC] THEN REWRITE_TAC[LIM] THEN MATCH_MP_TAC MONO_OR THEN REWRITE_TAC[] THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / norm(a:real^N)`) THEN ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; REAL_LT_RDIV_EQ] THEN REWRITE_TAC[dist; o_THM; GSYM LIFT_SUB; GSYM DOT_RSUB; NORM_LIFT] THEN ONCE_REWRITE_TAC[DOT_SYM] THEN MESON_TAC[NORM_CAUCHY_SCHWARZ_ABS; REAL_MUL_SYM; REAL_LET_TRANS]);;
let CONTINUOUS_AT_LIFT_DOT = 
prove (`!a:real^N x. (lift o (\y. a dot y)) continuous at x`,
REPEAT GEN_TAC THEN REWRITE_TAC[CONTINUOUS_AT; o_THM] THEN MATCH_MP_TAC LIM_LIFT_DOT THEN REWRITE_TAC[LIM_AT] THEN MESON_TAC[]);;
let CONTINUOUS_ON_LIFT_DOT = 
prove (`!s. (lift o (\y. a dot y)) continuous_on s`,
let CLOSED_INTERVAL_LEFT = 
prove (`!b:real^N. closed {x:real^N | !i. 1 <= i /\ i <= dimindex(:N) ==> x$i <= b$i}`,
REWRITE_TAC[CLOSED_LIMPT; LIMPT_APPROACHABLE; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN 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 `z <= b /\ b < x ==> x - b <= abs(z - x)`]);;
let CLOSED_INTERVAL_RIGHT = 
prove (`!a:real^N. closed {x:real^N | !i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= x$i}`,
REWRITE_TAC[CLOSED_LIMPT; LIMPT_APPROACHABLE; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `(a:real^N)$i - (x: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)`]);;
let CLOSED_HALFSPACE_LE = 
prove (`!a:real^N b. closed {x | a dot x <= b}`,
REPEAT GEN_TAC THEN MP_TAC(ISPEC `(:real^N)` CONTINUOUS_ON_LIFT_DOT) THEN REWRITE_TAC[CONTINUOUS_ON_CLOSED; GSYM CLOSED_IN; SUBTOPOLOGY_UNIV] THEN DISCH_THEN(MP_TAC o SPEC `IMAGE lift {r | ?x:real^N. (a dot x = r) /\ r <= b}`) THEN ANTS_TAC THENL [ALL_TAC; MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE; IN_UNIV] THEN REWRITE_TAC[o_DEF] THEN MESON_TAC[LIFT_DROP]] THEN REWRITE_TAC[CLOSED_IN_CLOSED] THEN EXISTS_TAC `{x | !i. 1 <= i /\ i <= dimindex(:1) ==> (x:real^1)$i <= (lift b)$i}` THEN REWRITE_TAC[CLOSED_INTERVAL_LEFT] THEN SIMP_TAC[EXTENSION; IN_IMAGE; IN_UNIV; IN_ELIM_THM; IN_INTER; VEC_COMPONENT; DIMINDEX_1; LAMBDA_BETA; o_THM] THEN SIMP_TAC[ARITH_RULE `1 <= i /\ i <= 1 <=> (i = 1)`] THEN REWRITE_TAC[GSYM drop; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN MESON_TAC[LIFT_DROP]);;
let CLOSED_HALFSPACE_GE = 
prove (`!a:real^N b. closed {x | a dot x >= b}`,
REWRITE_TAC[REAL_ARITH `a >= b <=> --a <= --b`] THEN REWRITE_TAC[GSYM DOT_LNEG; CLOSED_HALFSPACE_LE]);;
let CLOSED_HYPERPLANE = 
prove (`!a b. closed {x | a dot x = b}`,
REPEAT GEN_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN REWRITE_TAC[REAL_ARITH `b <= a dot x <=> a dot x >= b`] THEN REWRITE_TAC[SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN SIMP_TAC[CLOSED_INTER; CLOSED_HALFSPACE_LE; CLOSED_HALFSPACE_GE]);;
let CLOSED_STANDARD_HYPERPLANE = 
prove (`!k a. closed {x:real^N | x$k = a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] CLOSED_HYPERPLANE) THEN ASM_SIMP_TAC[DOT_BASIS]);;
let CLOSED_HALFSPACE_COMPONENT_LE = 
prove (`!a k. closed {x:real^N | x$k <= a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] CLOSED_HALFSPACE_LE) THEN ASM_SIMP_TAC[DOT_BASIS]);;
let CLOSED_HALFSPACE_COMPONENT_GE = 
prove (`!a k. closed {x:real^N | x$k >= a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] CLOSED_HALFSPACE_GE) THEN ASM_SIMP_TAC[DOT_BASIS]);;
(* ------------------------------------------------------------------------- *) (* Openness of halfspaces. *) (* ------------------------------------------------------------------------- *)
let OPEN_HALFSPACE_LT = 
prove (`!a b. open {x | a dot x < b}`,
REWRITE_TAC[GSYM REAL_NOT_LE] THEN REWRITE_TAC[SET_RULE `{x | ~p x} = UNIV DIFF {x | p x}`] THEN REWRITE_TAC[GSYM closed; GSYM real_ge; CLOSED_HALFSPACE_GE]);;
let OPEN_HALFSPACE_COMPONENT_LT = 
prove (`!a k. open {x:real^N | x$k < a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] OPEN_HALFSPACE_LT) THEN ASM_SIMP_TAC[DOT_BASIS]);;
let OPEN_HALFSPACE_GT = 
prove (`!a b. open {x | a dot x > b}`,
REWRITE_TAC[REAL_ARITH `x > y <=> ~(x <= y)`] THEN REWRITE_TAC[SET_RULE `{x | ~p x} = UNIV DIFF {x | p x}`] THEN REWRITE_TAC[GSYM closed; CLOSED_HALFSPACE_LE]);;
let OPEN_HALFSPACE_COMPONENT_GT = 
prove (`!a k. open {x:real^N | x$k > a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] OPEN_HALFSPACE_GT) THEN ASM_SIMP_TAC[DOT_BASIS]);;
let OPEN_POSITIVE_MULTIPLES = 
prove (`!s:real^N->bool. open s ==> open {c % x | &0 < c /\ x IN s}`,
REWRITE_TAC[open_def; FORALL_IN_GSPEC] THEN GEN_TAC THEN DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`c:real`; `x:real^N`] THEN STRIP_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 EXISTS_TAC `c * e:real` THEN ASM_SIMP_TAC[REAL_LT_MUL] THEN X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `inv(c) % y:real^N`) THEN ANTS_TAC THENL [SUBGOAL_THEN `x:real^N = inv c % c % x` SUBST1_TAC THENL [ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID; REAL_LT_IMP_NZ]; ASM_SIMP_TAC[DIST_MUL; real_abs; REAL_LT_INV_EQ; REAL_LT_IMP_LE] THEN ONCE_REWRITE_TAC[REAL_ARITH `inv c * x:real = x / c`] THEN ASM_MESON_TAC[REAL_LT_LDIV_EQ; REAL_MUL_SYM]]; DISCH_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN EXISTS_TAC `c:real` THEN EXISTS_TAC `inv(c) % y:real^N` THEN ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; REAL_LT_IMP_NZ] THEN VECTOR_ARITH_TAC]);;
(* ------------------------------------------------------------------------- *) (* Closures and interiors of halfspaces. *) (* ------------------------------------------------------------------------- *)
let INTERIOR_HALFSPACE_LE = 
prove (`!a:real^N b. ~(a = vec 0) ==> interior {x | a dot x <= b} = {x | a dot x < b}`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC INTERIOR_UNIQUE THEN SIMP_TAC[OPEN_HALFSPACE_LT; SUBSET; IN_ELIM_THM; REAL_LT_IMP_LE] THEN X_GEN_TAC `s:real^N->bool` THEN STRIP_TAC THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN ASM_SIMP_TAC[REAL_LT_LE] THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [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` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN REWRITE_TAC[SUBSET; IN_CBALL] THEN DISCH_THEN(MP_TAC o SPEC `x + e / norm(a) % a:real^N`) THEN REWRITE_TAC[NORM_ARITH `dist(x:real^N,x + y) = norm y`] THEN ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; REAL_DIV_RMUL; NORM_EQ_0; REAL_ARITH `&0 < x ==> abs x <= x`] THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `x + e / norm(a) % a:real^N`) THEN ASM_REWRITE_TAC[DOT_RADD; DOT_RMUL] THEN MATCH_MP_TAC(REAL_ARITH `&0 < e ==> ~(b + e <= b)`) THEN ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; NORM_POS_LT; DOT_POS_LT]);;
let INTERIOR_HALFSPACE_GE = 
prove (`!a:real^N b. ~(a = vec 0) ==> interior {x | a dot x >= b} = {x | a dot x > b}`,
REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[REAL_ARITH `a >= b <=> --a <= --b`; REAL_ARITH `a > b <=> --a < --b`] THEN ASM_SIMP_TAC[GSYM DOT_LNEG; INTERIOR_HALFSPACE_LE; VECTOR_NEG_EQ_0]);;
let INTERIOR_HALFSPACE_COMPONENT_LE = 
prove (`!a k. interior {x:real^N | x$k <= a} = {x | x$k < a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] INTERIOR_HALFSPACE_LE) THEN ASM_SIMP_TAC[DOT_BASIS; BASIS_NONZERO]);;
let INTERIOR_HALFSPACE_COMPONENT_GE = 
prove (`!a k. interior {x:real^N | x$k >= a} = {x | x$k > a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] INTERIOR_HALFSPACE_GE) THEN ASM_SIMP_TAC[DOT_BASIS; BASIS_NONZERO]);;
let CLOSURE_HALFSPACE_LT = 
prove (`!a:real^N b. ~(a = vec 0) ==> closure {x | a dot x < b} = {x | a dot x <= b}`,
REPEAT STRIP_TAC THEN REWRITE_TAC[CLOSURE_INTERIOR] THEN REWRITE_TAC[SET_RULE `UNIV DIFF {x | P x} = {x | ~P x}`] THEN ASM_SIMP_TAC[REAL_ARITH `~(x < b) <=> x >= b`; INTERIOR_HALFSPACE_GE] THEN REWRITE_TAC[EXTENSION; IN_DIFF; IN_UNIV; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
let CLOSURE_HALFSPACE_GT = 
prove (`!a:real^N b. ~(a = vec 0) ==> closure {x | a dot x > b} = {x | a dot x >= b}`,
REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[REAL_ARITH `a >= b <=> --a <= --b`; REAL_ARITH `a > b <=> --a < --b`] THEN ASM_SIMP_TAC[GSYM DOT_LNEG; CLOSURE_HALFSPACE_LT; VECTOR_NEG_EQ_0]);;
let CLOSURE_HALFSPACE_COMPONENT_LT = 
prove (`!a k. closure {x:real^N | x$k < a} = {x | x$k <= a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] CLOSURE_HALFSPACE_LT) THEN ASM_SIMP_TAC[DOT_BASIS; BASIS_NONZERO]);;
let CLOSURE_HALFSPACE_COMPONENT_GT = 
prove (`!a k. closure {x:real^N | x$k > a} = {x | x$k >= a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] CLOSURE_HALFSPACE_GT) THEN ASM_SIMP_TAC[DOT_BASIS; BASIS_NONZERO]);;
let INTERIOR_HYPERPLANE = 
prove (`!a b. ~(a = vec 0) ==> interior {x | a dot x = b} = {}`,
REWRITE_TAC[REAL_ARITH `x = y <=> x <= y /\ x >= y`] THEN REWRITE_TAC[SET_RULE `{x | p x /\ q x} = {x | p x} INTER {x | q x}`] THEN REWRITE_TAC[INTERIOR_INTER] THEN ASM_SIMP_TAC[INTERIOR_HALFSPACE_LE; INTERIOR_HALFSPACE_GE] THEN REWRITE_TAC[EXTENSION; IN_INTER; IN_ELIM_THM; NOT_IN_EMPTY] THEN REAL_ARITH_TAC);;
let FRONTIER_HALFSPACE_LE = 
prove (`!a:real^N b. ~(a = vec 0 /\ b = &0) ==> frontier {x | a dot x <= b} = {x | a dot x = b}`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THEN ASM_SIMP_TAC[DOT_LZERO] THENL [ASM_CASES_TAC `&0 <= b` THEN ASM_REWRITE_TAC[UNIV_GSPEC; FRONTIER_UNIV; EMPTY_GSPEC; FRONTIER_EMPTY]; ASM_SIMP_TAC[frontier; INTERIOR_HALFSPACE_LE; CLOSURE_CLOSED; CLOSED_HALFSPACE_LE] THEN REWRITE_TAC[EXTENSION; IN_DIFF; IN_ELIM_THM] THEN REAL_ARITH_TAC]);;
let FRONTIER_HALFSPACE_GE = 
prove (`!a:real^N b. ~(a = vec 0 /\ b = &0) ==> frontier {x | a dot x >= b} = {x | a dot x = b}`,
REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`--a:real^N`; `--b:real`] FRONTIER_HALFSPACE_LE) THEN ASM_REWRITE_TAC[VECTOR_NEG_EQ_0; REAL_NEG_EQ_0; DOT_LNEG] THEN REWRITE_TAC[REAL_LE_NEG2; REAL_EQ_NEG2; real_ge]);;
let FRONTIER_HALFSPACE_LT = 
prove (`!a:real^N b. ~(a = vec 0 /\ b = &0) ==> frontier {x | a dot x < b} = {x | a dot x = b}`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THEN ASM_SIMP_TAC[DOT_LZERO] THENL [ASM_CASES_TAC `&0 < b` THEN ASM_REWRITE_TAC[UNIV_GSPEC; FRONTIER_UNIV; EMPTY_GSPEC; FRONTIER_EMPTY]; ASM_SIMP_TAC[frontier; CLOSURE_HALFSPACE_LT; INTERIOR_OPEN; OPEN_HALFSPACE_LT] THEN REWRITE_TAC[EXTENSION; IN_DIFF; IN_ELIM_THM] THEN REAL_ARITH_TAC]);;
let FRONTIER_HALFSPACE_GT = 
prove (`!a:real^N b. ~(a = vec 0 /\ b = &0) ==> frontier {x | a dot x > b} = {x | a dot x = b}`,
REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`--a:real^N`; `--b:real`] FRONTIER_HALFSPACE_LT) THEN ASM_REWRITE_TAC[VECTOR_NEG_EQ_0; REAL_NEG_EQ_0; DOT_LNEG] THEN REWRITE_TAC[REAL_LT_NEG2; REAL_EQ_NEG2; real_gt]);;
let INTERIOR_STANDARD_HYPERPLANE = 
prove (`!k a. interior {x:real^N | x$k = a} = {}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !x:real^N. x$k = x$i` CHOOSE_TAC THENL [ASM_REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN MP_TAC(ISPECL [`basis i:real^N`; `a:real`] INTERIOR_HYPERPLANE) THEN ASM_SIMP_TAC[DOT_BASIS; BASIS_NONZERO]);;
let EMPTY_INTERIOR_LOWDIM = 
prove (`!s:real^N->bool. dim(s) < dimindex(:N) ==> interior s = {}`,
GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP LOWDIM_SUBSET_HYPERPLANE) THEN DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN MATCH_MP_TAC(SET_RULE `!t u. s SUBSET t /\ t SUBSET u /\ u = {} ==> s = {}`) THEN MAP_EVERY EXISTS_TAC [`interior(span(s):real^N->bool)`; `interior({x:real^N | a dot x = &0})`] THEN ASM_SIMP_TAC[SUBSET_INTERIOR; SPAN_INC; INTERIOR_HYPERPLANE]);;
(* ------------------------------------------------------------------------- *) (* Unboundedness of halfspaces. *) (* ------------------------------------------------------------------------- *)
let UNBOUNDED_HALFSPACE_COMPONENT_LE = 
prove (`!a k. ~bounded {x:real^N | x$k <= a}`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `?i. 1 <= i /\ i <= dimindex(:N) /\ !z:real^N. z$k = z$i` CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN ASM_REWRITE_TAC[bounded; FORALL_IN_GSPEC] THEN DISCH_THEN(X_CHOOSE_THEN `B:real` MP_TAC) THEN REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN EXISTS_TAC `--(&1 + max (abs B) (abs a)) % basis i:real^N` THEN ASM_SIMP_TAC[NORM_MUL; NORM_BASIS; BASIS_COMPONENT; VECTOR_MUL_COMPONENT] THEN REAL_ARITH_TAC);;
let UNBOUNDED_HALFSPACE_COMPONENT_GE = 
prove (`!a k. ~bounded {x:real^N | x$k >= a}`,
REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP BOUNDED_NEGATIONS) THEN MP_TAC(SPECL [`--a:real`; `k:num`] UNBOUNDED_HALFSPACE_COMPONENT_LE) THEN REWRITE_TAC[CONTRAPOS_THM] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN CONJ_TAC THENL [MESON_TAC[VECTOR_NEG_NEG]; REWRITE_TAC[IN_ELIM_THM; VECTOR_NEG_COMPONENT] THEN REAL_ARITH_TAC]);;
let UNBOUNDED_HALFSPACE_COMPONENT_LT = 
prove (`!a k. ~bounded {x:real^N | x$k < a}`,
let UNBOUNDED_HALFSPACE_COMPONENT_GT = 
prove (`!a k. ~bounded {x:real^N | x$k > a}`,
let BOUNDED_HALFSPACE_LE = 
prove (`!a:real^N b. bounded {x | a dot x <= b} <=> a = vec 0 /\ b < &0`,
GEOM_BASIS_MULTIPLE_TAC 1 `a:real^N` THEN SIMP_TAC[DOT_LMUL; DOT_BASIS; VECTOR_MUL_EQ_0; DIMINDEX_GE_1; LE_REFL; BASIS_NONZERO] THEN X_GEN_TAC `a:real` THEN ASM_CASES_TAC `a = &0` THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN X_GEN_TAC `b:real` THENL [REWRITE_TAC[REAL_MUL_LZERO; DOT_LZERO; GSYM REAL_NOT_LE] THEN ASM_CASES_TAC `&0 <= b` THEN ASM_REWRITE_TAC[BOUNDED_EMPTY; NOT_BOUNDED_UNIV; SET_RULE `{x | T} = UNIV`; EMPTY_GSPEC]; ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_LT_LE; UNBOUNDED_HALFSPACE_COMPONENT_LE]]);;
let BOUNDED_HALFSPACE_GE = 
prove (`!a:real^N b. bounded {x | a dot x >= b} <=> a = vec 0 /\ &0 < b`,
REWRITE_TAC[REAL_ARITH `a >= b <=> --a <= --b`] THEN REWRITE_TAC[GSYM DOT_LNEG; BOUNDED_HALFSPACE_LE] THEN REWRITE_TAC[VECTOR_NEG_EQ_0; REAL_ARITH `--b < &0 <=> &0 < b`]);;
let BOUNDED_HALFSPACE_LT = 
prove (`!a:real^N b. bounded {x | a dot x < b} <=> a = vec 0 /\ b <= &0`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THEN ASM_REWRITE_TAC[] THENL [REWRITE_TAC[DOT_LZERO; GSYM REAL_NOT_LE] THEN ASM_CASES_TAC `b <= &0` THEN ASM_REWRITE_TAC[BOUNDED_EMPTY; NOT_BOUNDED_UNIV; SET_RULE `{x | T} = UNIV`; EMPTY_GSPEC]; ONCE_REWRITE_TAC[GSYM BOUNDED_CLOSURE_EQ] THEN ASM_SIMP_TAC[CLOSURE_HALFSPACE_LT; BOUNDED_HALFSPACE_LE]]);;
let BOUNDED_HALFSPACE_GT = 
prove (`!a:real^N b. bounded {x | a dot x > b} <=> a = vec 0 /\ &0 <= b`,
REWRITE_TAC[REAL_ARITH `a > b <=> --a < --b`] THEN REWRITE_TAC[GSYM DOT_LNEG; BOUNDED_HALFSPACE_LT] THEN REWRITE_TAC[VECTOR_NEG_EQ_0; REAL_ARITH `--b <= &0 <=> &0 <= b`]);;
(* ------------------------------------------------------------------------- *) (* Equality of continuous functions on closure and related results. *) (* ------------------------------------------------------------------------- *)
let FORALL_IN_CLOSURE = 
prove (`!f:real^M->real^N s t. closed t /\ f continuous_on (closure s) /\ (!x. x IN s ==> f x IN t) ==> (!x. x IN closure s ==> f x IN t)`,
REWRITE_TAC[SET_RULE `(!x. x IN s ==> f x IN t) <=> s SUBSET {x | x IN s /\ f x IN t}`] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSURE_MINIMAL THEN ASM_REWRITE_TAC[CLOSED_CLOSURE] THEN CONJ_TAC THENL [MP_TAC(ISPEC `s:real^M->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[]; MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE THEN ASM_REWRITE_TAC[CLOSED_CLOSURE]]);;
let FORALL_IN_CLOSURE_EQ = 
prove (`!f s t. closed t /\ f continuous_on closure s ==> ((!x. x IN closure s ==> f x IN t) <=> (!x. x IN s ==> f x IN t))`,
let SUP_CLOSURE = 
prove (`!s. sup(IMAGE drop (closure s)) = sup(IMAGE drop s)`,
GEN_TAC THEN MATCH_MP_TAC SUP_EQ THEN REWRITE_TAC[FORALL_IN_IMAGE] THEN GEN_TAC THEN ONCE_REWRITE_TAC[SET_RULE `drop x <= b <=> x IN {x | drop x <= b}`] THEN MATCH_MP_TAC FORALL_IN_CLOSURE_EQ THEN REWRITE_TAC[CONTINUOUS_ON_ID; drop; CLOSED_HALFSPACE_COMPONENT_LE]);;
let INF_CLOSURE = 
prove (`!s. inf(IMAGE drop (closure s)) = inf(IMAGE drop s)`,
GEN_TAC THEN MATCH_MP_TAC INF_EQ THEN REWRITE_TAC[FORALL_IN_IMAGE] THEN GEN_TAC THEN ONCE_REWRITE_TAC[SET_RULE `b <= drop x <=> x IN {x | b <= drop x}`] THEN MATCH_MP_TAC FORALL_IN_CLOSURE_EQ THEN REWRITE_TAC[CONTINUOUS_ON_ID; drop; CLOSED_HALFSPACE_COMPONENT_GE; GSYM real_ge]);;
let CONTINUOUS_LE_ON_CLOSURE = 
prove (`!f:real^M->real s a. (lift o f) continuous_on closure(s) /\ (!x. x IN s ==> f(x) <= a) ==> !x. x IN closure(s) ==> f(x) <= a`,
let lemma = prove
   (`x IN s ==> f x <= a <=> x IN s ==> (lift o f) x IN {y | y$1 <= a}`,
    REWRITE_TAC[IN_ELIM_THM; o_THM; GSYM drop; LIFT_DROP]) in
  REWRITE_TAC[lemma] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
  MATCH_MP_TAC FORALL_IN_CLOSURE THEN
  ASM_REWRITE_TAC[ETA_AX; CLOSED_HALFSPACE_COMPONENT_LE]);;
let CONTINUOUS_GE_ON_CLOSURE = 
prove (`!f:real^M->real s a. (lift o f) continuous_on closure(s) /\ (!x. x IN s ==> a <= f(x)) ==> !x. x IN closure(s) ==> a <= f(x)`,
let lemma = prove
   (`x IN s ==> a <= f x <=> x IN s ==> (lift o f) x IN {y | y$1 >= a}`,
    REWRITE_TAC[IN_ELIM_THM; o_THM; GSYM drop; real_ge; LIFT_DROP]) in
  REWRITE_TAC[lemma] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
  MATCH_MP_TAC FORALL_IN_CLOSURE THEN
  ASM_REWRITE_TAC[ETA_AX; CLOSED_HALFSPACE_COMPONENT_GE]);;
let CONTINUOUS_CONSTANT_ON_CLOSURE = 
prove (`!f:real^M->real^N s a. f continuous_on closure(s) /\ (!x. x IN s ==> f(x) = a) ==> !x. x IN closure(s) ==> f(x) = a`,
REWRITE_TAC[SET_RULE `x IN s ==> f x = a <=> x IN s ==> f x IN {a}`] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC FORALL_IN_CLOSURE THEN ASM_REWRITE_TAC[CLOSED_SING]);;
let CONTINUOUS_AGREE_ON_CLOSURE = 
prove (`!g h:real^M->real^N. g continuous_on closure s /\ h continuous_on closure s /\ (!x. x IN s ==> g x = h x) ==> !x. x IN closure s ==> g x = h x`,
REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_CONSTANT_ON_CLOSURE THEN ASM_SIMP_TAC[CONTINUOUS_ON_SUB]);;
let CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT = 
prove (`!f:real^M->real^N s a. f continuous_on s ==> closed_in (subtopology euclidean s) {x | x IN s /\ f x = a}`,
REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[SET_RULE `{x | x IN s /\ f(x) = a} = {x | x IN s /\ f(x) IN {a}}`] THEN MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE THEN ASM_REWRITE_TAC[CLOSED_SING]);;
let CONTINUOUS_CLOSED_PREIMAGE_CONSTANT = 
prove (`!f:real^M->real^N s. f continuous_on s /\ closed s ==> closed {x | x IN s /\ f(x) = a}`,
REPEAT STRIP_TAC THEN ASM_CASES_TAC `{x | x IN s /\ (f:real^M->real^N)(x) = a} = {}` THEN ASM_REWRITE_TAC[CLOSED_EMPTY] THEN ONCE_REWRITE_TAC[SET_RULE `{x | x IN s /\ f(x) = a} = {x | x IN s /\ f(x) IN {a}}`] THEN MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE THEN ASM_REWRITE_TAC[CLOSED_SING] THEN ASM SET_TAC[]);;
(* ------------------------------------------------------------------------- *) (* 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 CONTINUOUS_ON_CLOSURE_SEQUENTIALLY = 
prove (`!f:real^M->real^N s. f continuous_on closure s <=> !x a. a IN closure s /\ (!n. x n IN s) /\ (x --> a) sequentially ==> ((f o x) --> f a) sequentially`,
REWRITE_TAC[CONTINUOUS_ON_CLOSURE] THEN REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN REWRITE_TAC[IMP_IMP; GSYM continuous_within] THEN REWRITE_TAC[CONTINUOUS_WITHIN_SEQUENTIALLY] THEN MESON_TAC[]);;
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. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_AT_SQRT = 
prove (`!a s. &0 < drop a ==> (lift o sqrt o drop) continuous (at a)`,
REPEAT STRIP_TAC THEN REWRITE_TAC[continuous_at; o_THM; DIST_LIFT] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `min (drop a) (e * sqrt(drop a))` THEN ASM_SIMP_TAC[REAL_LT_MIN; SQRT_POS_LT; REAL_LT_MUL; DIST_REAL] THEN X_GEN_TAC `b:real^1` THEN REWRITE_TAC[GSYM drop] THEN STRIP_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP (REAL_ARITH `abs(b - a) < a ==> &0 < b`)) THEN SUBGOAL_THEN `sqrt(drop b) - sqrt(drop a) = (drop b - drop a) / (sqrt(drop a) + sqrt(drop b))` SUBST1_TAC THENL [MATCH_MP_TAC(REAL_FIELD `sa pow 2 = a /\ sb pow 2 = b /\ &0 < sa /\ &0 < sb ==> sb - sa = (b - a) / (sa + sb)`) THEN ASM_SIMP_TAC[SQRT_POS_LT; SQRT_POW_2; REAL_LT_IMP_LE]; ASM_SIMP_TAC[REAL_ABS_DIV; SQRT_POS_LT; REAL_LT_ADD; REAL_LT_LDIV_EQ; REAL_ARITH `&0 < x ==> abs x = x`] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] REAL_LTE_TRANS)) THEN ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LE_ADDR; SQRT_POS_LE; REAL_LT_IMP_LE]]);;
let CONTINUOUS_WITHIN_LIFT_SQRT = 
prove (`!a s. (!x. x IN s ==> &0 <= drop x) ==> (lift o sqrt o drop) continuous (at a within s)`,
REPEAT STRIP_TAC THEN REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (REAL_ARITH `drop a < &0 \/ drop a = &0 \/ &0 < drop a`) THENL [MATCH_MP_TAC CONTINUOUS_WITHIN_SUBSET THEN EXISTS_TAC `{x | &0 <= drop x}` THEN ASM_SIMP_TAC[SUBSET; IN_ELIM_THM] THEN MATCH_MP_TAC CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL THEN ASM_REWRITE_TAC[IN_ELIM_THM; REAL_NOT_LE] THEN REWRITE_TAC[drop; REWRITE_RULE[real_ge] CLOSED_HALFSPACE_COMPONENT_GE]; RULE_ASSUM_TAC(REWRITE_RULE[GSYM LIFT_EQ; LIFT_DROP; LIFT_NUM]) THEN ASM_REWRITE_TAC[continuous_within; o_THM; DROP_VEC; SQRT_0; LIFT_NUM] THEN REWRITE_TAC[DIST_0; NORM_LIFT; NORM_REAL; GSYM drop] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `(e:real) pow 2` THEN ASM_SIMP_TAC[REAL_POW_LT] THEN X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN ASM_SIMP_TAC[real_abs; SQRT_POS_LE] THEN SUBGOAL_THEN `e = sqrt(e pow 2)` SUBST1_TAC THENL [ASM_SIMP_TAC[POW_2_SQRT; REAL_LT_IMP_LE]; MATCH_MP_TAC SQRT_MONO_LT THEN ASM_SIMP_TAC[] THEN ASM_REAL_ARITH_TAC]; MATCH_MP_TAC CONTINUOUS_AT_WITHIN THEN MATCH_MP_TAC CONTINUOUS_AT_SQRT THEN ASM_REWRITE_TAC[]]);;
let CONTINUOUS_WITHIN_SQRT_COMPOSE = 
prove (`!f s a:real^N. (\x. lift(f x)) continuous (at a within s) /\ (&0 < f a \/ !x. x IN s ==> &0 <= f x) ==> (\x. lift(sqrt(f x))) continuous (at a within s)`,
REPEAT GEN_TAC THEN SUBGOAL_THEN `(\x:real^N. lift(sqrt(f x))) = (lift o sqrt o drop) o (lift o f)` SUBST1_TAC THENL [REWRITE_TAC[o_DEF; LIFT_DROP]; ALL_TAC] THEN REPEAT STRIP_TAC THEN (MATCH_MP_TAC CONTINUOUS_WITHIN_COMPOSE THEN CONJ_TAC THENL [ASM_REWRITE_TAC[o_DEF]; ALL_TAC]) THENL [MATCH_MP_TAC CONTINUOUS_AT_WITHIN THEN MATCH_MP_TAC CONTINUOUS_AT_SQRT THEN ASM_REWRITE_TAC[o_DEF; LIFT_DROP]; MATCH_MP_TAC CONTINUOUS_WITHIN_LIFT_SQRT THEN ASM_REWRITE_TAC[FORALL_IN_IMAGE; o_DEF; LIFT_DROP]]);;
let CONTINUOUS_AT_SQRT_COMPOSE = 
prove (`!f a:real^N. (\x. lift(f x)) continuous (at a) /\ (&0 < f a \/ !x. &0 <= f x) ==> (\x. lift(sqrt(f x))) continuous (at a)`,
REPEAT GEN_TAC THEN MP_TAC(ISPECL [`f:real^N->real`; `(:real^N)`; `a:real^N`] CONTINUOUS_WITHIN_SQRT_COMPOSE) THEN REWRITE_TAC[WITHIN_UNIV; IN_UNIV]);;
let CONTINUOUS_ON_LIFT_SQRT = 
prove (`!s. (!x. x IN s ==> &0 <= drop x) ==> (lift o sqrt o drop) continuous_on s`,
let CONTINUOUS_ON_LIFT_SQRT_COMPOSE = 
prove (`!f:real^N->real s. (lift o f) continuous_on s /\ (!x. x IN s ==> &0 <= f x) ==> (\x. lift(sqrt(f x))) continuous_on s`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `(\x:real^N. lift(sqrt(f x))) = (lift o sqrt o drop) o (lift o f)` SUBST1_TAC THENL [REWRITE_TAC[o_DEF; LIFT_DROP]; MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_ON_LIFT_SQRT THEN ASM_REWRITE_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP]]);;
(* ------------------------------------------------------------------------- *) (* Cauchy continuity, and the extension of functions to closures. *) (* ------------------------------------------------------------------------- *)
let UNIFORMLY_CONTINUOUS_IMP_CAUCHY_CONTINUOUS = 
prove (`!f:real^M->real^N s. f uniformly_continuous_on s ==> (!x. cauchy x /\ (!n. (x n) IN s) ==> cauchy(f o x))`,
REPEAT GEN_TAC THEN REWRITE_TAC[uniformly_continuous_on; cauchy; o_DEF] THEN MESON_TAC[]);;
let CONTINUOUS_CLOSED_IMP_CAUCHY_CONTINUOUS = 
prove (`!f:real^M->real^N s. f continuous_on s /\ closed s ==> (!x. cauchy x /\ (!n. (x n) IN s) ==> cauchy(f o x))`,
REWRITE_TAC[GSYM COMPLETE_EQ_CLOSED; CONTINUOUS_ON_SEQUENTIALLY] THEN REWRITE_TAC[complete] THEN MESON_TAC[CONVERGENT_IMP_CAUCHY]);;
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]]);;
let CAUCHY_CONTINUOUS_EXTENDS_TO_CLOSURE = 
prove (`!f:real^M->real^N s. (!x. cauchy x /\ (!n. (x n) IN s) ==> cauchy(f o x)) ==> ?g. g continuous_on closure s /\ (!x. x IN s ==> g x = f x)`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `!a:real^M. ?x. a IN closure s ==> (!n. x n IN s) /\ (x --> a) sequentially` MP_TAC THENL [MESON_TAC[CLOSURE_SEQUENTIAL]; ALL_TAC] THEN REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `X:real^M->num->real^M` THEN DISCH_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP CAUCHY_CONTINUOUS_UNIQUENESS_LEMMA) THEN DISCH_THEN(MP_TAC o GEN `a:real^M` o SPECL [`a:real^M`; `(X:real^M->num->real^M) a`]) THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[] `(!a. P a ==> Q a) ==> ((!a. P a ==> R a) ==> p) ==> ((!a. Q a ==> R a) ==> p)`)) 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 `g:real^M->real^N` THEN STRIP_TAC THEN MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL [X_GEN_TAC `a:real^M` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `a:real^M`) THEN ASM_SIMP_TAC[REWRITE_RULE[SUBSET] CLOSURE_SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `(\n. a):num->real^M` o CONJUNCT2) THEN ASM_SIMP_TAC[LIM_CONST_EQ; o_DEF; TRIVIAL_LIMIT_SEQUENTIALLY]; STRIP_TAC] THEN ASM_SIMP_TAC[CONTINUOUS_ON_CLOSURE_SEQUENTIALLY] THEN MAP_EVERY X_GEN_TAC [`x:num->real^M`; `a:real^M`] THEN STRIP_TAC THEN MATCH_MP_TAC LIM_TRANSFORM_EVENTUALLY THEN EXISTS_TAC `(f:real^M->real^N) o (x:num->real^M)` THEN ASM_SIMP_TAC[] THEN MATCH_MP_TAC ALWAYS_EVENTUALLY THEN ASM_SIMP_TAC[o_THM]);;
let UNIFORMLY_CONTINUOUS_EXTENDS_TO_CLOSURE = 
prove (`!f:real^M->real^N s. f uniformly_continuous_on s ==> ?g. g uniformly_continuous_on closure s /\ (!x. x IN s ==> g x = f x) /\ !h. h continuous_on closure s /\ (!x. x IN s ==> h x = f x) ==> !x. x IN closure s ==> h x = g x`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP CAUCHY_CONTINUOUS_EXTENDS_TO_CLOSURE o MATCH_MP UNIFORMLY_CONTINUOUS_IMP_CAUCHY_CONTINUOUS) THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^M->real^N` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_MESON_TAC[UNIFORMLY_CONTINUOUS_ON_CLOSURE; UNIFORMLY_CONTINUOUS_ON_EQ]; ASM_MESON_TAC[CONTINUOUS_AGREE_ON_CLOSURE]]);;
let CAUCHY_CONTINUOUS_IMP_CONTINUOUS = 
prove (`!f:real^M->real^N s. (!x. cauchy x /\ (!n. (x n) IN s) ==> cauchy(f o x)) ==> f continuous_on s`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(CHOOSE_TAC o MATCH_MP CAUCHY_CONTINUOUS_EXTENDS_TO_CLOSURE) THEN ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; CLOSURE_SUBSET; CONTINUOUS_ON_EQ]);;
let BOUNDED_UNIFORMLY_CONTINUOUS_IMAGE = 
prove (`!f:real^M->real^N s. f uniformly_continuous_on s /\ bounded s ==> bounded(IMAGE f s)`,
REPEAT STRIP_TAC THEN FIRST_ASSUM (MP_TAC o MATCH_MP UNIFORMLY_CONTINUOUS_EXTENDS_TO_CLOSURE) THEN DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC) THEN MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `IMAGE (g:real^M->real^N) (closure s)` THEN CONJ_TAC THENL [ASM_MESON_TAC[COMPACT_CLOSURE; UNIFORMLY_CONTINUOUS_IMP_CONTINUOUS; COMPACT_IMP_BOUNDED; COMPACT_CONTINUOUS_IMAGE]; MP_TAC(ISPEC `s:real^M->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[]]);;
(* ------------------------------------------------------------------------- *) (* 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]]);;
let CONTINUOUS_AT_TRANSLATION = 
prove (`!a z f:real^M->real^N. f continuous at (a + z) <=> (\x. f(a + x)) continuous at z`,
REPEAT GEN_TAC THEN MATCH_MP_TAC CONTINUOUS_AT_COMPOSE_EQ THEN EXISTS_TAC `\x:real^M. x - a` THEN SIMP_TAC[CONTINUOUS_ADD; CONTINUOUS_SUB; CONTINUOUS_AT_ID; CONTINUOUS_CONST] THEN VECTOR_ARITH_TAC);;
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)`,
REPEAT GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM(ASSUME_TAC o GEN_REWRITE_RULE I [GSYM ORTHOGONAL_TRANSFORMATION]) THEN FIRST_ASSUM(X_CHOOSE_TAC `g:real^M->real^M` o MATCH_MP ORTHOGONAL_TRANSFORMATION_INVERSE) THEN MATCH_MP_TAC CONTINUOUS_AT_COMPOSE_EQ THEN EXISTS_TAC `g:real^M->real^M` THEN RULE_ASSUM_TAC(REWRITE_RULE[ORTHOGONAL_TRANSFORMATION]) THEN ASM_SIMP_TAC[LINEAR_CONTINUOUS_AT]);;
add_linear_invariants [CONTINUOUS_AT_LINEAR_IMAGE];; (* ------------------------------------------------------------------------- *) (* Interior of an injective image. *) (* ------------------------------------------------------------------------- *)
let INTERIOR_IMAGE_SUBSET = 
prove (`!f:real^M->real^N s. (!x. f continuous at x) /\ (!x y. f x = f y ==> x = y) ==> interior(IMAGE f s) SUBSET IMAGE f (interior s)`,
REPEAT STRIP_TAC THEN REWRITE_TAC[SUBSET] THEN REWRITE_TAC[interior; IN_ELIM_THM] THEN X_GEN_TAC `y:real^N` THEN DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN REWRITE_TAC[IN_IMAGE; IN_ELIM_THM] THEN SUBGOAL_THEN `y IN IMAGE (f:real^M->real^N) s` MP_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN REWRITE_TAC[IN_IMAGE] THEN MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[IN_ELIM_THM] THEN FIRST_X_ASSUM SUBST_ALL_TAC THEN EXISTS_TAC `{x | (f:real^M->real^N)(x) IN t}` THEN REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_OPEN_PREIMAGE_UNIV THEN ASM_MESON_TAC[]; ASM SET_TAC[]]);;
(* ------------------------------------------------------------------------- *) (* 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)`,
MP_TAC CONTINUOUS_WITHIN_AVOID THEN REPLICATE_TAC 2 (MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN DISCH_THEN(MP_TAC o SPEC `(:real^M)`) THEN MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN REWRITE_TAC[WITHIN_UNIV; IN_UNIV]);;
let CONTINUOUS_ON_AVOID = 
prove (`!f:real^M->real^N x s a. f continuous_on s /\ x IN s /\ ~(f x = a) ==> ?e. &0 < e /\ !y. y IN s /\ dist(x,y) < e ==> ~(f y = a)`,
REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_WITHIN_AVOID THEN ASM_SIMP_TAC[]);;
let CONTINUOUS_ON_OPEN_AVOID = 
prove (`!f:real^M->real^N x s a. f continuous_on s /\ open s /\ x IN s /\ ~(f x = a) ==> ?e. &0 < e /\ !y. dist(x,y) < e ==> ~(f y = a)`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `open(s:real^M->bool)` THEN ASM_SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_AT_AVOID THEN ASM_SIMP_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Proving a function is constant by proving open-ness of level set. *) (* ------------------------------------------------------------------------- *)
let CONTINUOUS_LEVELSET_OPEN_IN_CASES = 
prove (`!f:real^M->real^N s a. connected s /\ f continuous_on s /\ open_in (subtopology euclidean s) {x | x IN s /\ f x = a} ==> (!x. x IN s ==> ~(f x = a)) \/ (!x. x IN s ==> f x = a)`,
REWRITE_TAC[SET_RULE `(!x. x IN s ==> ~(f x = a)) <=> {x | x IN s /\ f x = a} = {}`; SET_RULE `(!x. x IN s ==> f x = a) <=> {x | x IN s /\ f x = a} = s`] THEN REWRITE_TAC[CONNECTED_CLOPEN] THEN REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT]);;
let CONTINUOUS_LEVELSET_OPEN_IN = 
prove (`!f:real^M->real^N s a. connected s /\ f continuous_on s /\ open_in (subtopology euclidean s) {x | x IN s /\ f x = a} /\ (?x. x IN s /\ f x = a) ==> (!x. x IN s ==> f x = a)`,
let CONTINUOUS_LEVELSET_OPEN = 
prove (`!f:real^M->real^N s a. connected s /\ f continuous_on s /\ open {x | x IN s /\ f x = a} /\ (?x. x IN s /\ f x = a) ==> (!x. x IN s ==> f x = a)`,
REPEAT GEN_TAC THEN DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN MATCH_MP_TAC CONTINUOUS_LEVELSET_OPEN_IN THEN ASM_REWRITE_TAC[OPEN_IN_OPEN] THEN EXISTS_TAC `{x | x IN s /\ (f:real^M->real^N) x = a}` THEN ASM_REWRITE_TAC[] THEN SET_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Some arithmetical combinations (more to prove). *) (* ------------------------------------------------------------------------- *)
let OPEN_SCALING = 
prove (`!s:real^N->bool c. ~(c = &0) /\ open s ==> open(IMAGE (\x. c % x) s)`,
REPEAT GEN_TAC THEN REWRITE_TAC[open_def; FORALL_IN_IMAGE] THEN STRIP_TAC 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[] THEN DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN EXISTS_TAC `e * abs(c)` THEN ASM_SIMP_TAC[REAL_LT_MUL; GSYM REAL_ABS_NZ] THEN X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `inv(c) % y:real^N` THEN ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; VECTOR_MUL_LID] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN SUBGOAL_THEN `x = inv(c) % c % x:real^N` SUBST1_TAC THENL [ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID]; REWRITE_TAC[dist; GSYM VECTOR_SUB_LDISTRIB; NORM_MUL] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[REAL_ABS_INV] THEN ASM_SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ; GSYM REAL_ABS_NZ] THEN ASM_REWRITE_TAC[GSYM dist]]);;
let OPEN_NEGATIONS = 
prove (`!s:real^N->bool. open s ==> open (IMAGE (--) s)`,
SUBGOAL_THEN `(--) = \x:real^N. --(&1) % x` (fun th -> SIMP_TAC[th; OPEN_SCALING; REAL_ARITH `~(--(&1) = &0)`]) THEN REWRITE_TAC[FUN_EQ_THM] THEN VECTOR_ARITH_TAC);;
let OPEN_TRANSLATION = 
prove (`!s a:real^N. open s ==> open(IMAGE (\x. a + x) s)`,
REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`\x:real^N. x - a`; `s:real^N->bool`] CONTINUOUS_OPEN_PREIMAGE_UNIV) THEN ASM_SIMP_TAC[CONTINUOUS_SUB; CONTINUOUS_AT_ID; CONTINUOUS_CONST] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE; IN_UNIV] THEN ASM_MESON_TAC[VECTOR_ARITH `(a + x) - a = x:real^N`; VECTOR_ARITH `a + (x - a) = x:real^N`]);;
let OPEN_TRANSLATION_EQ = 
prove (`!a s. open (IMAGE (\x:real^N. a + x) s) <=> open s`,
REWRITE_TAC[open_def] THEN GEOM_TRANSLATE_TAC[]);;
add_translation_invariants [OPEN_TRANSLATION_EQ];;
let OPEN_AFFINITY = 
prove (`!s a:real^N c. open s /\ ~(c = &0) ==> open (IMAGE (\x. a + c % x) s)`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `(\x:real^N. a + c % x) = (\x. a + x) o (\x. c % x)` SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN ASM_SIMP_TAC[IMAGE_o; OPEN_TRANSLATION; OPEN_SCALING]);;
let INTERIOR_TRANSLATION = 
prove (`!a:real^N s. interior (IMAGE (\x. a + x) s) = IMAGE (\x. a + x) (interior s)`,
REWRITE_TAC[interior] THEN GEOM_TRANSLATE_TAC[]);;
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_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) INTER u = {})}))`,
REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN GEN_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `t DIFF u:real^N->bool`) THEN MATCH_MP_TAC MONO_IMP THEN SIMP_TAC[OPEN_IN_DIFF; CLOSED_IN_DIFF; OPEN_IN_REFL; CLOSED_IN_REFL] THENL [REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ]; REWRITE_TAC[closed_in]] THEN REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY; SUBSET_RESTRICT] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]);;
let LOWER_HEMICONTINUOUS = 
prove (`!f:real^M->real^N->bool t s. (!x. x IN s ==> f(x) SUBSET t) ==> ((!u. closed_in (subtopology euclidean t) u ==> closed_in (subtopology euclidean s) {x | x IN s /\ f(x) SUBSET u}) <=> (!u. open_in (subtopology euclidean t) u ==> open_in (subtopology euclidean s) {x | x IN s /\ ~(f(x) INTER u = {})}))`,
REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN GEN_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `t DIFF u:real^N->bool`) THEN MATCH_MP_TAC MONO_IMP THEN SIMP_TAC[OPEN_IN_DIFF; CLOSED_IN_DIFF; OPEN_IN_REFL; CLOSED_IN_REFL] THENL [REWRITE_TAC[closed_in]; REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ]] THEN REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY; SUBSET_RESTRICT] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]);;
let OPEN_MAP_IFF_LOWER_HEMICONTINUOUS_PREIMAGE = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> ((!u. open_in (subtopology euclidean s) u ==> open_in (subtopology euclidean t) (IMAGE f u)) <=> (!u. closed_in (subtopology euclidean s) u ==> closed_in (subtopology euclidean t) {y | y IN t /\ {x | x IN s /\ f x = y} SUBSET u}))`,
REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL [X_GEN_TAC `v:real^M->bool` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `s DIFF v:real^M->bool`) THEN ASM_SIMP_TAC[OPEN_IN_DIFF; OPEN_IN_REFL] THEN REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]; X_GEN_TAC `v:real^M->bool` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `s DIFF v:real^M->bool`) THEN ASM_SIMP_TAC[CLOSED_IN_DIFF; CLOSED_IN_REFL] THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN DISCH_THEN(fun th -> CONJ_TAC THENL [ASM SET_TAC[]; MP_TAC th]) THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]]);;
let CLOSED_MAP_IFF_UPPER_HEMICONTINUOUS_PREIMAGE = 
prove (`!f:real^M->real^N s t. IMAGE f s SUBSET t ==> ((!u. closed_in (subtopology euclidean s) u ==> closed_in (subtopology euclidean t) (IMAGE f u)) <=> (!u. open_in (subtopology euclidean s) u ==> open_in (subtopology euclidean t) {y | y IN t /\ {x | x IN s /\ f x = y} SUBSET u}))`,
REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL [X_GEN_TAC `v:real^M->bool` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `s DIFF v:real^M->bool`) THEN ASM_SIMP_TAC[CLOSED_IN_DIFF; CLOSED_IN_REFL] THEN REWRITE_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]; X_GEN_TAC `v:real^M->bool` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `s DIFF v:real^M->bool`) THEN ASM_SIMP_TAC[OPEN_IN_DIFF; OPEN_IN_REFL] THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN REWRITE_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN DISCH_THEN(fun th -> CONJ_TAC THENL [ASM SET_TAC[]; MP_TAC th]) THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]]);;
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)`,
REPEAT STRIP_TAC THEN UNDISCH_TAC `!u. open_in (subtopology euclidean t) u ==> open_in (subtopology euclidean s) {x | x IN s /\ (f:real^M->real^N->bool)(x) SUBSET u}` THEN DISCH_THEN(MP_TAC o SPEC `t INTER {a + b | a IN (f:real^M->real^N->bool) x /\ b IN ball(vec 0,e)}`) THEN SIMP_TAC[OPEN_SUMS; OPEN_BALL; OPEN_IN_OPEN_INTER] THEN REWRITE_TAC[open_in; SUBSET_RESTRICT] THEN DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN ASM_SIMP_TAC[IN_ELIM_THM; SUBSET_INTER] THEN ANTS_TAC THENL [REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN ASM_MESON_TAC[CENTRE_IN_BALL; VECTOR_ADD_RID]; DISCH_THEN(X_CHOOSE_THEN `d1:real` (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "1")))] THEN UNDISCH_TAC `!u. closed_in (subtopology euclidean t) u ==> closed_in (subtopology euclidean s) {x | x IN s /\ (f:real^M->real^N->bool)(x) SUBSET u}` THEN ASM_SIMP_TAC[LOWER_HEMICONTINUOUS] THEN DISCH_THEN(MP_TAC o GEN `a:real^N` o SPEC `t INTER ball(a:real^N,e / &2)`) THEN SIMP_TAC[OPEN_BALL; OPEN_IN_OPEN_INTER] THEN MP_TAC(SPEC `closure((f:real^M->real^N->bool) x)` COMPACT_EQ_HEINE_BOREL) THEN ASM_REWRITE_TAC[COMPACT_CLOSURE] THEN DISCH_THEN(MP_TAC o SPEC `{ball(a:real^N,e / &2) | a IN (f:real^M->real^N->bool) x}`) THEN REWRITE_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; OPEN_BALL] THEN ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN REWRITE_TAC[EXISTS_FINITE_SUBSET_IMAGE] THEN ANTS_TAC THENL [REWRITE_TAC[CLOSURE_APPROACHABLE; SUBSET; UNIONS_IMAGE; IN_ELIM_THM] THEN REWRITE_TAC[IN_BALL] THEN ASM_SIMP_TAC[REAL_HALF]; ALL_TAC] THEN DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` STRIP_ASSUME_TAC) THEN DISCH_TAC THEN FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP (MESON[CLOSURE_SUBSET; SUBSET_TRANS] `closure s SUBSET t ==> s SUBSET t`)) THEN SUBGOAL_THEN `open_in (subtopology euclidean s) (INTERS {{x | x IN s /\ ~((f:real^M->real^N->bool) x INTER t INTER ball(a,e / &2) = {})} | a IN c})` MP_TAC THENL [MATCH_MP_TAC OPEN_IN_INTERS THEN ASM_SIMP_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; FINITE_IMAGE] THEN ASM_REWRITE_TAC[IMAGE_EQ_EMPTY] THEN ASM SET_TAC[]; ALL_TAC] THEN REWRITE_TAC[open_in] THEN DISCH_THEN(MP_TAC o SPEC `x:real^M` o CONJUNCT2) THEN ANTS_TAC THENL [REWRITE_TAC[INTERS_GSPEC; IN_ELIM_THM] THEN X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN ASM_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL; REAL_HALF] THEN ASM SET_TAC[]; DISCH_THEN(X_CHOOSE_THEN `d2:real` (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "2")))] 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 CONJ_TAC THENL [ALL_TAC; REMOVE_THEN "1" (MP_TAC o SPEC `x':real^M`) THEN ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ASM_MESON_TAC[DIST_SYM]; ALL_TAC] THEN REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_BALL] THEN REWRITE_TAC[VECTOR_ARITH `x:real^N = a + b <=> x - a = b`; DIST_0; ONCE_REWRITE_RULE[CONJ_SYM] UNWIND_THM1] THEN REWRITE_TAC[dist]] THEN REMOVE_THEN "2" (MP_TAC o SPEC `x':real^M`) THEN ASM_REWRITE_TAC[INTERS_GSPEC; IN_ELIM_THM] THEN ANTS_TAC THENL [ASM_MESON_TAC[DIST_SYM]; ALL_TAC] THEN DISCH_THEN(LABEL_TAC "3") THEN X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN UNDISCH_TAC `(f:real^M->real^N->bool) x SUBSET UNIONS (IMAGE (\a. ball (a,e / &2)) c)` THEN REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `y:real^N`) THEN ASM_REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM; IN_BALL] THEN DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN REMOVE_THEN "3" (MP_TAC o SPEC `a:real^N`) THEN ASM_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER; IN_BALL] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:real^N` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[DIST_TRIANGLE_HALF_L; DIST_SYM]);;
(* ------------------------------------------------------------------------- *) (* Connected components, considered as a "connectedness" relation or a set. *) (* ------------------------------------------------------------------------- *)
let connected_component = new_definition
 `connected_component s x y <=>
        ?t. connected t /\ t SUBSET s /\ x IN t /\ y IN t`;;
let CONNECTED_COMPONENT_IN = 
prove (`!s x y. connected_component s x y ==> x IN s /\ y IN s`,
REWRITE_TAC[connected_component] THEN SET_TAC[]);;
let CONNECTED_COMPONENT_REFL = 
prove (`!s x:real^N. x IN s ==> connected_component s x x`,
REWRITE_TAC[connected_component] THEN REPEAT STRIP_TAC THEN EXISTS_TAC `{x:real^N}` THEN REWRITE_TAC[CONNECTED_SING] THEN ASM SET_TAC[]);;
let CONNECTED_COMPONENT_REFL_EQ = 
prove (`!s x:real^N. connected_component s x x <=> x IN s`,
REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[CONNECTED_COMPONENT_REFL] THEN REWRITE_TAC[connected_component] THEN SET_TAC[]);;
let CONNECTED_COMPONENT_SYM = 
prove (`!s x y:real^N. connected_component s x y ==> connected_component s y x`,
REWRITE_TAC[connected_component] THEN MESON_TAC[]);;
let CONNECTED_COMPONENT_TRANS = 
prove (`!s x y:real^N. connected_component s x y /\ connected_component s y z ==> connected_component s x z`,
REPEAT GEN_TAC THEN REWRITE_TAC[connected_component] THEN DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `t:real^N->bool`) (X_CHOOSE_TAC `u:real^N->bool`)) THEN EXISTS_TAC `t UNION u:real^N->bool` THEN ASM_REWRITE_TAC[IN_UNION; UNION_SUBSET] THEN MATCH_MP_TAC CONNECTED_UNION THEN ASM SET_TAC[]);;
let CONNECTED_COMPONENT_OF_SUBSET = 
prove (`!s t x. s SUBSET t /\ connected_component s x y ==> connected_component t x y`,
REWRITE_TAC[connected_component] THEN SET_TAC[]);;
let CONNECTED_COMPONENT_SET = 
prove (`!s x. connected_component s x = { y | ?t. connected t /\ t SUBSET s /\ x IN t /\ y IN t}`,
REWRITE_TAC[IN_ELIM_THM; EXTENSION] THEN REWRITE_TAC[IN; connected_component] THEN MESON_TAC[]);;
let CONNECTED_COMPONENT_UNIONS = 
prove (`!s x. connected_component s x = UNIONS {t | connected t /\ x IN t /\ t SUBSET s}`,
REWRITE_TAC[CONNECTED_COMPONENT_SET] THEN SET_TAC[]);;
let CONNECTED_COMPONENT_SUBSET = 
prove (`!s x. (connected_component s x) SUBSET s`,
REWRITE_TAC[CONNECTED_COMPONENT_SET] THEN SET_TAC[]);;
let CONNECTED_CONNECTED_COMPONENT_SET = 
prove (`!s. connected s <=> !x:real^N. x IN s ==> connected_component s x = s`,
GEN_TAC THEN REWRITE_TAC[CONNECTED_COMPONENT_UNIONS] THEN EQ_TAC THENL [SET_TAC[]; ALL_TAC] THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_REWRITE_TAC[CONNECTED_EMPTY] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN DISCH_THEN(MP_TAC o SPEC `a:real^N`) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_MP_TAC CONNECTED_UNIONS THEN ASM SET_TAC[]);;
let CONNECTED_COMPONENT_EQ_SELF = 
prove (`!s x. connected s /\ x IN s ==> connected_component s x = s`,
let CONNECTED_IFF_CONNECTED_COMPONENT = 
prove (`!s. connected s <=> !x y. x IN s /\ y IN s ==> connected_component s x y`,
REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT_SET] THEN REWRITE_TAC[EXTENSION] THEN MESON_TAC[IN; CONNECTED_COMPONENT_IN]);;
let CONNECTED_COMPONENT_MAXIMAL = 
prove (`!s t x:real^N. x IN t /\ connected t /\ t SUBSET s ==> t SUBSET (connected_component s x)`,
REWRITE_TAC[CONNECTED_COMPONENT_SET] THEN SET_TAC[]);;
let CONNECTED_COMPONENT_MONO = 
prove (`!s t x. s SUBSET t ==> (connected_component s x) SUBSET (connected_component t x)`,
REWRITE_TAC[CONNECTED_COMPONENT_SET] THEN SET_TAC[]);;
let CONNECTED_CONNECTED_COMPONENT = 
prove (`!s x. connected(connected_component s x)`,
REWRITE_TAC[CONNECTED_COMPONENT_UNIONS] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_UNIONS THEN SET_TAC[]);;
let CONNECTED_COMPONENT_EQ_EMPTY = 
prove (`!s x:real^N. connected_component s x = {} <=> ~(x IN s)`,
REPEAT GEN_TAC THEN EQ_TAC THENL [REWRITE_TAC[EXTENSION; NOT_IN_EMPTY] THEN DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN REWRITE_TAC[IN; CONNECTED_COMPONENT_REFL_EQ]; REWRITE_TAC[CONNECTED_COMPONENT_SET] THEN SET_TAC[]]);;
let CONNECTED_COMPONENT_EMPTY = 
prove (`!x. connected_component {} x = {}`,
let CONNECTED_COMPONENT_EQ = 
prove (`!s x y. y IN connected_component s x ==> (connected_component s y = connected_component s x)`,
let CLOSED_CONNECTED_COMPONENT = 
prove (`!s x:real^N. closed s ==> closed(connected_component s x)`,
REPEAT STRIP_TAC THEN ASM_CASES_TAC `(x:real^N) IN s` THENL [ALL_TAC; ASM_MESON_TAC[CONNECTED_COMPONENT_EQ_EMPTY; CLOSED_EMPTY]] THEN REWRITE_TAC[GSYM CLOSURE_EQ] THEN MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[CLOSURE_SUBSET] THEN MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN SIMP_TAC[CONNECTED_CLOSURE; CONNECTED_CONNECTED_COMPONENT] THEN CONJ_TAC THENL [MATCH_MP_TAC(REWRITE_RULE[SUBSET] CLOSURE_SUBSET) THEN ASM_REWRITE_TAC[IN; CONNECTED_COMPONENT_REFL_EQ]; MATCH_MP_TAC CLOSURE_MINIMAL THEN ASM_REWRITE_TAC[CONNECTED_COMPONENT_SUBSET]]);;
let CONNECTED_COMPONENT_DISJOINT = 
prove (`!s a b. DISJOINT (connected_component s a) (connected_component s b) <=> ~(a IN connected_component s b)`,
REWRITE_TAC[DISJOINT; EXTENSION; IN_INTER; NOT_IN_EMPTY] THEN REWRITE_TAC[IN] THEN MESON_TAC[CONNECTED_COMPONENT_SYM; CONNECTED_COMPONENT_TRANS]);;
let CONNECTED_COMPONENT_NONOVERLAP = 
prove (`!s a b:real^N. (connected_component s a) INTER (connected_component s b) = {} <=> ~(a IN s) \/ ~(b IN s) \/ ~(connected_component s a = connected_component s b)`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `(a:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN RULE_ASSUM_TAC(REWRITE_RULE[GSYM CONNECTED_COMPONENT_EQ_EMPTY]) THEN ASM_REWRITE_TAC[INTER_EMPTY] THEN ASM_CASES_TAC `(b:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN RULE_ASSUM_TAC(REWRITE_RULE[GSYM CONNECTED_COMPONENT_EQ_EMPTY]) THEN ASM_REWRITE_TAC[INTER_EMPTY] THEN ASM_CASES_TAC `connected_component s (a:real^N) = connected_component s b` THEN ASM_REWRITE_TAC[INTER_IDEMPOT; CONNECTED_COMPONENT_EQ_EMPTY] THEN FIRST_X_ASSUM(MP_TAC o check(is_neg o concl)) THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN REWRITE_TAC[] THEN MATCH_MP_TAC CONNECTED_COMPONENT_EQ THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [GSYM DISJOINT]) THEN REWRITE_TAC[CONNECTED_COMPONENT_DISJOINT]);;
let CONNECTED_COMPONENT_OVERLAP = 
prove (`!s a b:real^N. ~((connected_component s a) INTER (connected_component s b) = {}) <=> a IN s /\ b IN s /\ connected_component s a = connected_component s b`,
REWRITE_TAC[CONNECTED_COMPONENT_NONOVERLAP; DE_MORGAN_THM]);;
let CONNECTED_COMPONENT_SYM_EQ = 
prove (`!s x y. connected_component s x y <=> connected_component s y x`,
let CONNECTED_COMPONENT_EQ_EQ = 
prove (`!s x y:real^N. connected_component s x = connected_component s y <=> ~(x IN s) /\ ~(y IN s) \/ x IN s /\ y IN s /\ connected_component s x y`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `(y:real^N) IN s` THENL [ASM_CASES_TAC `(x:real^N) IN s` THEN ASM_REWRITE_TAC[] THENL [REWRITE_TAC[FUN_EQ_THM] THEN ASM_MESON_TAC[CONNECTED_COMPONENT_TRANS; CONNECTED_COMPONENT_REFL; CONNECTED_COMPONENT_SYM]; ASM_MESON_TAC[CONNECTED_COMPONENT_EQ_EMPTY]]; RULE_ASSUM_TAC(REWRITE_RULE[GSYM CONNECTED_COMPONENT_EQ_EMPTY]) THEN ASM_REWRITE_TAC[CONNECTED_COMPONENT_EQ_EMPTY] THEN ONCE_REWRITE_TAC[CONNECTED_COMPONENT_SYM_EQ] THEN ASM_REWRITE_TAC[EMPTY] THEN ASM_MESON_TAC[CONNECTED_COMPONENT_EQ_EMPTY]]);;
let CONNECTED_EQ_CONNECTED_COMPONENT_EQ = 
prove (`!s. connected s <=> !x y. x IN s /\ y IN s ==> connected_component s x = connected_component s y`,
let CONNECTED_COMPONENT_IDEMP = 
prove (`!s x:real^N. connected_component (connected_component s x) x = connected_component s x`,
REWRITE_TAC[FUN_EQ_THM; connected_component] THEN REPEAT GEN_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[CONNECTED_COMPONENT_MAXIMAL; SUBSET_TRANS; CONNECTED_COMPONENT_SUBSET]);;
let CONNECTED_COMPONENT_UNIQUE = 
prove (`!s c x:real^N. x IN c /\ c SUBSET s /\ connected c /\ (!c'. x IN c' /\ c' SUBSET s /\ connected c' ==> c' SUBSET c) ==> connected_component s x = c`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL [FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[CONNECTED_COMPONENT_SUBSET; CONNECTED_CONNECTED_COMPONENT] THEN REWRITE_TAC[IN] THEN ASM_REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ] THEN ASM SET_TAC[]; MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN ASM_REWRITE_TAC[]]);;
let JOINABLE_CONNECTED_COMPONENT_EQ = 
prove (`!s t x y:real^N. connected t /\ t SUBSET s /\ ~(connected_component s x INTER t = {}) /\ ~(connected_component s y INTER t = {}) ==> connected_component s x = connected_component s y`,
REPEAT GEN_TAC THEN REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `w:real^N` STRIP_ASSUME_TAC) (X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC)) THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_COMPONENT_EQ THEN REWRITE_TAC[IN] THEN MATCH_MP_TAC CONNECTED_COMPONENT_TRANS THEN EXISTS_TAC `z:real^N` THEN CONJ_TAC THENL [ASM_MESON_TAC[IN]; ALL_TAC] THEN MATCH_MP_TAC CONNECTED_COMPONENT_TRANS THEN EXISTS_TAC `w:real^N` THEN CONJ_TAC THENL [REWRITE_TAC[connected_component] THEN EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[]; ASM_MESON_TAC[IN; CONNECTED_COMPONENT_SYM]]);;
let CONNECTED_COMPONENT_TRANSLATION = 
prove (`!a s x. connected_component (IMAGE (\x. a + x) s) (a + x) = IMAGE (\x. a + x) (connected_component s x)`,
REWRITE_TAC[CONNECTED_COMPONENT_SET] THEN GEOM_TRANSLATE_TAC[]);;
add_translation_invariants [CONNECTED_COMPONENT_TRANSLATION];;
let CONNECTED_COMPONENT_LINEAR_IMAGE = 
prove (`!f s x. linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y) ==> connected_component (IMAGE f s) (f x) = IMAGE f (connected_component s x)`,
REWRITE_TAC[CONNECTED_COMPONENT_SET] THEN GEOM_TRANSFORM_TAC[]);;
add_linear_invariants [CONNECTED_COMPONENT_LINEAR_IMAGE];;
let UNIONS_CONNECTED_COMPONENT = 
prove (`!s:real^N->bool. UNIONS {connected_component s x |x| x IN s} = s`,
GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC; CONNECTED_COMPONENT_SUBSET] THEN REWRITE_TAC[SUBSET; UNIONS_GSPEC; IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[] THEN REWRITE_TAC[IN] THEN ASM_REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ]);;
let COMPLEMENT_CONNECTED_COMPONENT_UNIONS = 
prove (`!s x:real^N. s DIFF connected_component s x = UNIONS({connected_component s y | y | y IN s} DELETE (connected_component s x))`,
REPEAT GEN_TAC THEN GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM UNIONS_CONNECTED_COMPONENT] THEN MATCH_MP_TAC(SET_RULE `(!x. x IN s DELETE a ==> DISJOINT a x) ==> UNIONS s DIFF a = UNIONS (s DELETE a)`) THEN REWRITE_TAC[IMP_CONJ; FORALL_IN_GSPEC; IN_DELETE] THEN SIMP_TAC[CONNECTED_COMPONENT_DISJOINT; CONNECTED_COMPONENT_EQ_EQ] THEN MESON_TAC[IN; SUBSET; CONNECTED_COMPONENT_SUBSET]);;
let CLOSED_IN_CONNECTED_COMPONENT = 
prove (`!s x:real^N. closed_in (subtopology euclidean s) (connected_component s x)`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `connected_component s (x:real^N) = {}` THEN ASM_REWRITE_TAC[CLOSED_IN_EMPTY] THEN RULE_ASSUM_TAC(REWRITE_RULE[CONNECTED_COMPONENT_EQ_EMPTY]) THEN REWRITE_TAC[CLOSED_IN_CLOSED] THEN EXISTS_TAC `closure(connected_component s x):real^N->bool` THEN REWRITE_TAC[CLOSED_CLOSURE] THEN MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[SUBSET_INTER; CONNECTED_COMPONENT_SUBSET; CLOSURE_SUBSET] THEN MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN REWRITE_TAC[INTER_SUBSET] THEN CONJ_TAC THENL [ASM_REWRITE_TAC[IN_INTER] THEN MATCH_MP_TAC(REWRITE_RULE[SUBSET] CLOSURE_SUBSET) THEN ASM_REWRITE_TAC[IN; CONNECTED_COMPONENT_REFL_EQ]; MATCH_MP_TAC CONNECTED_INTERMEDIATE_CLOSURE THEN EXISTS_TAC `connected_component s (x:real^N)` THEN REWRITE_TAC[INTER_SUBSET; CONNECTED_CONNECTED_COMPONENT; SUBSET_INTER; CONNECTED_COMPONENT_SUBSET; CLOSURE_SUBSET]]);;
let OPEN_IN_CONNECTED_COMPONENT = 
prove (`!s x:real^N. FINITE {connected_component s x |x| x IN s} ==> open_in (subtopology euclidean s) (connected_component s x)`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `connected_component s (x:real^N) = s DIFF (UNIONS {connected_component s y |y| y IN s} DIFF connected_component s x)` SUBST1_TAC THENL [REWRITE_TAC[UNIONS_CONNECTED_COMPONENT] THEN MATCH_MP_TAC(SET_RULE `t SUBSET s ==> t = s DIFF (s DIFF t)`) THEN REWRITE_TAC[CONNECTED_COMPONENT_SUBSET]; MATCH_MP_TAC OPEN_IN_DIFF THEN REWRITE_TAC[OPEN_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; SUBSET_UNIV] THEN REWRITE_TAC[UNIONS_DIFF] THEN MATCH_MP_TAC CLOSED_IN_UNIONS THEN REWRITE_TAC[FORALL_IN_GSPEC] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN SUBGOAL_THEN `connected_component s y DIFF connected_component s x = connected_component s y \/ connected_component s (y:real^N) DIFF connected_component s x = {}` (DISJ_CASES_THEN SUBST1_TAC) THENL [MATCH_MP_TAC(SET_RULE `(~(s INTER t = {}) ==> s = t) ==> s DIFF t = s \/ s DIFF t = {}`) THEN SIMP_TAC[CONNECTED_COMPONENT_OVERLAP]; REWRITE_TAC[CLOSED_IN_CONNECTED_COMPONENT]; REWRITE_TAC[CLOSED_IN_EMPTY]]]);;
let CONNECTED_COMPONENT_EQUIVALENCE_RELATION = 
prove (`!R s:real^N->bool. (!x y. R x y ==> R y x) /\ (!x y z. R x y /\ R y z ==> R x z) /\ (!a. a IN s ==> ?t. open_in (subtopology euclidean s) t /\ a IN t /\ !x. x IN t ==> R a x) ==> !a b. connected_component s a b ==> R a b`,
REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`R:real^N->real^N->bool`; `connected_component s (a:real^N)`] CONNECTED_EQUIVALENCE_RELATION) THEN ASM_REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT] THEN ANTS_TAC THENL [X_GEN_TAC `c:real^N` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `c:real^N`) THEN ANTS_TAC THENL [ASM_MESON_TAC[CONNECTED_COMPONENT_SUBSET; SUBSET]; ALL_TAC] THEN DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN EXISTS_TAC `t INTER connected_component s (a:real^N)` THEN ASM_SIMP_TAC[IN_INTER; OPEN_IN_OPEN] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_OPEN]) THEN MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`] CONNECTED_COMPONENT_SUBSET) THEN SET_TAC[]; DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN] THEN REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ] THEN ASM_MESON_TAC[CONNECTED_COMPONENT_IN]]);;
let CONNECTED_COMPONENT_INTERMEDIATE_SUBSET = 
prove (`!t u a:real^N. connected_component u a SUBSET t /\ t SUBSET u ==> connected_component t a = connected_component u a`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `(a:real^N) IN u` THENL [REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_COMPONENT_UNIQUE THEN ASM_REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT] THEN CONJ_TAC THENL [ASM_MESON_TAC[CONNECTED_COMPONENT_REFL; IN]; ALL_TAC] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN ASM SET_TAC[]; ASM_MESON_TAC[CONNECTED_COMPONENT_EQ_EMPTY; SUBSET]]);;
(* ------------------------------------------------------------------------- *) (* The set of connected components of a set. *) (* ------------------------------------------------------------------------- *)
let components = new_definition
  `components s = {connected_component s x | x | x:real^N IN s}`;;
let COMPONENTS_TRANSLATION = 
prove (`!a s. components(IMAGE (\x. a + x) s) = IMAGE (IMAGE (\x. a + x)) (components s)`,
REWRITE_TAC[components] THEN GEOM_TRANSLATE_TAC[] THEN SET_TAC[]);;
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 UNIONS_COMPONENTS = 
prove (`!u:real^N->bool. u = UNIONS (components u)`,
REWRITE_TAC[EXTENSION] THEN REPEAT GEN_TAC THEN EQ_TAC THENL[DISCH_TAC THEN REWRITE_TAC[IN_UNIONS] THEN EXISTS_TAC `connected_component (u:real^N->bool) x` THEN CONJ_TAC THENL [REWRITE_TAC[components] THEN SET_TAC[ASSUME `x:real^N IN u`]; REWRITE_TAC[CONNECTED_COMPONENT_SET] THEN SUBGOAL_THEN `?s:real^N->bool. connected s /\ s SUBSET u /\ x IN s` MP_TAC THENL[EXISTS_TAC `{x:real^N}` THEN ASM_REWRITE_TAC[CONNECTED_SING] THEN POP_ASSUM MP_TAC THEN SET_TAC[]; SET_TAC[]]]; REWRITE_TAC[IN_UNIONS] THEN STRIP_TAC THEN MATCH_MP_TAC (SET_RULE `!x:real^N s u. x IN s /\ s SUBSET u ==> x IN u`) THEN EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[] THEN STRIP_ASSUME_TAC (MESON[IN_COMPONENTS;ASSUME `t:real^N->bool IN components u`] `?y. t:real^N->bool = connected_component u y`) THEN ASM_REWRITE_TAC[CONNECTED_COMPONENT_SUBSET]]);;
let PAIRWISE_DISJOINT_COMPONENTS = 
prove (`!u:real^N->bool. pairwise DISJOINT (components u)`,
GEN_TAC THEN REWRITE_TAC[pairwise;DISJOINT] THEN MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `t:real^N->bool`] THEN STRIP_TAC THEN ASSERT_TAC `(?a. s:real^N->bool = connected_component u a) /\ ?b. t:real^N->bool = connected_component u b` THENL [ASM_MESON_TAC[IN_COMPONENTS]; ASM_MESON_TAC[CONNECTED_COMPONENT_NONOVERLAP]]);;
let IN_COMPONENTS_NONEMPTY = 
prove (`!s c. c IN components s ==> ~(c = {})`,
REPEAT GEN_TAC THEN REWRITE_TAC[components; IN_ELIM_THM] THEN STRIP_TAC THEN ASM_REWRITE_TAC[CONNECTED_COMPONENT_EQ_EMPTY]);;
let IN_COMPONENTS_SUBSET = 
prove (`!s c. c IN components s ==> c SUBSET s`,
REPEAT GEN_TAC THEN REWRITE_TAC[components; IN_ELIM_THM] THEN STRIP_TAC THEN ASM_REWRITE_TAC[CONNECTED_COMPONENT_SUBSET]);;
let IN_COMPONENTS_CONNECTED = 
prove (`!s c. c IN components s ==> connected c`,
REPEAT GEN_TAC THEN REWRITE_TAC[components; IN_ELIM_THM] THEN STRIP_TAC THEN ASM_REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT]);;
let IN_COMPONENTS_MAXIMAL = 
prove (`!s c:real^N->bool. c IN components s <=> ~(c = {}) /\ c SUBSET s /\ connected c /\ !c'. ~(c' = {}) /\ c SUBSET c' /\ c' SUBSET s /\ connected c' ==> c' = c`,
REPEAT GEN_TAC THEN REWRITE_TAC[components; IN_ELIM_THM] THEN EQ_TAC THENL [DISCH_THEN(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN ASM_REWRITE_TAC[CONNECTED_COMPONENT_EQ_EMPTY; CONNECTED_COMPONENT_SUBSET; CONNECTED_CONNECTED_COMPONENT] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN ASM_MESON_TAC[CONNECTED_COMPONENT_REFL; IN; SUBSET]; 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 DISCH_TAC THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN MATCH_MP_TAC(GSYM CONNECTED_COMPONENT_UNIQUE) THEN ASM_REWRITE_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 REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN MATCH_MP_TAC CONNECTED_UNION THEN ASM SET_TAC[]]);;
let JOINABLE_COMPONENTS_EQ = 
prove (`!s t c1 c2. connected t /\ t SUBSET s /\ c1 IN components s /\ c2 IN components s /\ ~(c1 INTER t = {}) /\ ~(c2 INTER t = {}) ==> c1 = c2`,
REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; components; FORALL_IN_GSPEC] THEN MESON_TAC[JOINABLE_CONNECTED_COMPONENT_EQ]);;
let CLOSED_IN_COMPONENT = 
prove (`!s c:real^N->bool. c IN components s ==> closed_in (subtopology euclidean s) c`,
REWRITE_TAC[components; FORALL_IN_GSPEC; CLOSED_IN_CONNECTED_COMPONENT]);;
let CLOSED_COMPONENTS = 
prove (`!s c. closed s /\ c IN components s ==> closed c`,
REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; components; FORALL_IN_GSPEC] THEN SIMP_TAC[CLOSED_CONNECTED_COMPONENT]);;
let COMPACT_COMPONENTS = 
prove (`!s c:real^N->bool. compact s /\ c IN components s ==> compact c`,
let CONTINUOUS_ON_COMPONENTS_GEN = 
prove (`!f:real^M->real^N s. (!c. c IN components s ==> open_in (subtopology euclidean s) c /\ f continuous_on c) ==> f continuous_on s`,
REPEAT GEN_TAC THEN REWRITE_TAC[CONTINUOUS_OPEN_IN_PREIMAGE_EQ] THEN DISCH_TAC THEN X_GEN_TAC `t:real^N->bool` THEN DISCH_TAC THEN SUBGOAL_THEN `{x | x IN s /\ (f:real^M->real^N) x IN t} = UNIONS {{x | x IN c /\ f x IN t} | c IN components s}` SUBST1_TAC THENL [CONV_TAC(LAND_CONV(SUBS_CONV [ISPEC `s:real^M->bool` UNIONS_COMPONENTS])) THEN REWRITE_TAC[UNIONS_GSPEC; IN_UNIONS] THEN SET_TAC[]; MATCH_MP_TAC OPEN_IN_UNIONS THEN REWRITE_TAC[FORALL_IN_GSPEC] THEN ASM_MESON_TAC[OPEN_IN_TRANS]]);;
let CONTINUOUS_ON_COMPONENTS_FINITE = 
prove (`!f:real^M->real^N s. FINITE(components s) /\ (!c. c IN components s ==> f continuous_on c) ==> f continuous_on s`,
REPEAT GEN_TAC THEN REWRITE_TAC[CONTINUOUS_CLOSED_IN_PREIMAGE_EQ] THEN DISCH_TAC THEN X_GEN_TAC `t:real^N->bool` THEN DISCH_TAC THEN SUBGOAL_THEN `{x | x IN s /\ (f:real^M->real^N) x IN t} = UNIONS {{x | x IN c /\ f x IN t} | c IN components s}` SUBST1_TAC THENL [CONV_TAC(LAND_CONV(SUBS_CONV [ISPEC `s:real^M->bool` UNIONS_COMPONENTS])) THEN REWRITE_TAC[UNIONS_GSPEC; IN_UNIONS] THEN SET_TAC[]; MATCH_MP_TAC CLOSED_IN_UNIONS THEN ASM_SIMP_TAC[SIMPLE_IMAGE; FINITE_IMAGE; FORALL_IN_IMAGE] THEN ASM_MESON_TAC[CLOSED_IN_TRANS; CLOSED_IN_COMPONENT]]);;
let COMPONENTS_NONOVERLAP = 
prove (`!s c c'. c IN components s /\ c' IN components s ==> (c INTER c' = {} <=> ~(c = c'))`,
REWRITE_TAC[components; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CONNECTED_COMPONENT_NONOVERLAP]);;
let COMPONENTS_EQ = 
prove (`!s c c'. c IN components s /\ c' IN components s ==> (c = c' <=> ~(c INTER c' = {}))`,
MESON_TAC[COMPONENTS_NONOVERLAP]);;
let COMPONENTS_EQ_EMPTY = 
prove (`!s. components s = {} <=> s = {}`,
GEN_TAC THEN REWRITE_TAC[EXTENSION] THEN REWRITE_TAC[components; connected_component; IN_ELIM_THM] THEN SET_TAC[]);;
let COMPONENTS_EMPTY = 
prove (`components {} = {}`,
REWRITE_TAC[COMPONENTS_EQ_EMPTY]);;
let CONNECTED_EQ_CONNECTED_COMPONENTS_EQ = 
prove (`!s. connected s <=> !c c'. c IN components s /\ c' IN components s ==> c = c'`,
REWRITE_TAC[components; IN_ELIM_THM] THEN MESON_TAC[CONNECTED_EQ_CONNECTED_COMPONENT_EQ]);;
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 CONNECTED_EQ_COMPONENTS_SUBSET_SING = 
prove (`!s:real^N->bool. connected s <=> components s SUBSET {s}`,
GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_REWRITE_TAC[COMPONENTS_EMPTY; CONNECTED_EMPTY; EMPTY_SUBSET] THEN REWRITE_TAC[SET_RULE `s SUBSET {a} <=> s = {} \/ s = {a}`] THEN ASM_REWRITE_TAC[COMPONENTS_EQ_EMPTY; COMPONENTS_EQ_SING]);;
let CONNECTED_EQ_COMPONENTS_SUBSET_SING_EXISTS = 
prove (`!s:real^N->bool. connected s <=> ?a. components s SUBSET {a}`,
GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_REWRITE_TAC[COMPONENTS_EMPTY; CONNECTED_EMPTY; EMPTY_SUBSET] THEN REWRITE_TAC[SET_RULE `s SUBSET {a} <=> s = {} \/ s = {a}`] THEN ASM_REWRITE_TAC[COMPONENTS_EQ_EMPTY; COMPONENTS_EQ_SING_EXISTS]);;
let IN_COMPONENTS_SELF = 
prove (`!s:real^N->bool. s IN components s <=> connected s /\ ~(s = {})`,
GEN_TAC THEN EQ_TAC THENL [MESON_TAC[IN_COMPONENTS_NONEMPTY; IN_COMPONENTS_CONNECTED]; SIMP_TAC[GSYM COMPONENTS_EQ_SING; IN_SING]]);;
let COMPONENTS_MAXIMAL = 
prove (`!s t c:real^N->bool. c IN components s /\ connected t /\ t SUBSET s /\ ~(c INTER t = {}) ==> t SUBSET c`,
REWRITE_TAC[IMP_CONJ; components; FORALL_IN_GSPEC] THEN REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN REWRITE_TAC[IN_INTER; LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP CONNECTED_COMPONENT_EQ) THEN MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN ASM_REWRITE_TAC[]);;
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 COMPONENTS_UNIQUE_EQ = 
prove (`!s:real^N->bool k. components s = k <=> UNIONS k = s /\ (!c. c IN k ==> connected c /\ ~(c = {}) /\ !c'. connected c' /\ c SUBSET c' /\ c' SUBSET s ==> c' = c)`,
REPEAT GEN_TAC THEN EQ_TAC THENL [DISCH_THEN(SUBST1_TAC o SYM); REWRITE_TAC[COMPONENTS_UNIQUE]] THEN REWRITE_TAC[GSYM UNIONS_COMPONENTS] THEN X_GEN_TAC `c:real^N->bool` THEN DISCH_TAC THEN REPEAT CONJ_TAC THENL [ASM_MESON_TAC[IN_COMPONENTS_CONNECTED]; ASM_MESON_TAC[IN_COMPONENTS_NONEMPTY]; RULE_ASSUM_TAC(REWRITE_RULE[IN_COMPONENTS_MAXIMAL]) THEN ASM_MESON_TAC[SUBSET_EMPTY]]);;
let EXISTS_COMPONENT_SUPERSET = 
prove (`!s t:real^N->bool. t SUBSET s /\ ~(s = {}) /\ connected t ==> ?c. c IN components s /\ t SUBSET c`,
REPEAT STRIP_TAC THEN ASM_CASES_TAC `t:real^N->bool = {}` THENL [ASM_REWRITE_TAC[EMPTY_SUBSET] THEN ASM_MESON_TAC[COMPONENTS_EQ_EMPTY; MEMBER_NOT_EMPTY]; FIRST_X_ASSUM(X_CHOOSE_TAC `a:real^N` o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN EXISTS_TAC `connected_component s (a:real^N)` THEN REWRITE_TAC[IN_COMPONENTS] THEN CONJ_TAC THENL [ASM SET_TAC[]; ASM_MESON_TAC[CONNECTED_COMPONENT_MAXIMAL]]]);;
let COMPONENTS_INTERMEDIATE_SUBSET = 
prove (`!s t u:real^N->bool. s IN components u /\ s SUBSET t /\ t SUBSET u ==> s IN components t`,
let IN_COMPONENTS_UNIONS_COMPLEMENT = 
prove (`!s c:real^N->bool. c IN components s ==> s DIFF c = UNIONS(components s DELETE c)`,
let CONNECTED_SUBSET_CLOPEN = 
prove (`!u s c:real^N->bool. closed_in (subtopology euclidean u) s /\ open_in (subtopology euclidean u) s /\ connected c /\ c SUBSET u /\ ~(c INTER s = {}) ==> c SUBSET s`,
REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONNECTED_CLOSED_IN]) THEN REWRITE_TAC[NOT_EXISTS_THM] THEN DISCH_THEN(MP_TAC o SPECL [`c INTER s:real^N->bool`; `c DIFF s:real^N->bool`]) THEN ASM_REWRITE_TAC[CONJ_ASSOC; SET_RULE `c DIFF s = {} <=> c SUBSET s`] THEN MATCH_MP_TAC(TAUT `p ==> ~(p /\ ~q) ==> q`) THEN REPLICATE_TAC 2 (CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]]) THEN CONJ_TAC THENL [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CLOSED_IN_CLOSED]); 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 REWRITE_TAC[OPEN_IN_OPEN; CLOSED_IN_CLOSED] THENL [EXISTS_TAC `t:real^N->bool`; EXISTS_TAC `(:real^N) DIFF t`] THEN ASM_REWRITE_TAC[GSYM OPEN_CLOSED] THEN ASM SET_TAC[]);;
let CLOPEN_UNIONS_COMPONENTS = 
prove (`!u s:real^N->bool. closed_in (subtopology euclidean u) s /\ open_in (subtopology euclidean u) s ==> ?k. k SUBSET components u /\ s = UNIONS k`,
REPEAT STRIP_TAC THEN EXISTS_TAC `{c:real^N->bool | c IN components u /\ ~(c INTER s = {})}` THEN REWRITE_TAC[SUBSET_RESTRICT] THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL [MP_TAC(ISPEC `u:real^N->bool` UNIONS_COMPONENTS) THEN FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN SET_TAC[]; REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_SUBSET_CLOPEN THEN EXISTS_TAC `u:real^N->bool` THEN ASM_MESON_TAC[IN_COMPONENTS_CONNECTED; IN_COMPONENTS_SUBSET]]);;
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);;
let COMPACT_UNIFORMLY_CONTINUOUS = 
prove (`!f:real^M->real^N s. f continuous_on s /\ compact s ==> f uniformly_continuous_on s`,
REPEAT GEN_TAC THEN REWRITE_TAC[continuous_on; uniformly_continuous_on] THEN STRIP_TAC THEN MP_TAC(ISPECL [`{f:real^M->real^N}`; `s:real^M->bool`] COMPACT_UNIFORMLY_EQUICONTINUOUS) THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ; IN_SING; FORALL_UNWIND_THM2] THEN ASM_MESON_TAC[]);;
(* ------------------------------------------------------------------------- *) (* 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 *) (* ------------------------------------------------------------------------- *)
let OPEN_LIFT = 
prove (`!s. open(IMAGE lift s) <=> !x. x IN s ==> ?e. &0 < e /\ !x'. abs(x' - x) < e ==> x' IN s`,
let LIMPT_APPROACHABLE_LIFT = 
prove (`!x s. (lift x) limit_point_of (IMAGE lift s) <=> !e. &0 < e ==> ?x'. x' IN s /\ ~(x' = x) /\ abs(x' - x) < e`,
let CLOSED_LIFT = 
prove (`!s. closed (IMAGE lift s) <=> !x. (!e. &0 < e ==> ?x'. x' IN s /\ ~(x' = x) /\ abs(x' - x) < e) ==> x IN s`,
GEN_TAC THEN REWRITE_TAC[CLOSED_LIMPT; LIMPT_APPROACHABLE] THEN ONCE_REWRITE_TAC[FORALL_LIFT] THEN REWRITE_TAC[LIMPT_APPROACHABLE_LIFT; LIFT_EQ; DIST_LIFT; EXISTS_LIFT; LIFT_IN_IMAGE_LIFT]);;
let CONTINUOUS_AT_LIFT_RANGE = 
prove (`!f x. (lift o f) continuous (at x) <=> !e. &0 < e ==> ?d. &0 < d /\ (!x'. norm(x' - x) < d ==> abs(f x' - f x) < e)`,
REWRITE_TAC[continuous_at; o_THM; DIST_LIFT] THEN REWRITE_TAC[dist]);;
let CONTINUOUS_ON_LIFT_RANGE = 
prove (`!f s. (lift o f) continuous_on s <=> !x. x IN s ==> !e. &0 < e ==> ?d. &0 < d /\ (!x'. x' IN s /\ norm(x' - x) < d ==> abs(f x' - f x) < e)`,
REWRITE_TAC[continuous_on; o_THM; DIST_LIFT] THEN REWRITE_TAC[dist]);;
let CONTINUOUS_LIFT_NORM_COMPOSE = 
prove (`!net f:A->real^N. f continuous net ==> (\x. lift(norm(f x))) continuous net`,
REPEAT GEN_TAC THEN REWRITE_TAC[continuous; tendsto] 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[DIST_REAL; GSYM drop; LIFT_DROP] THEN NORM_ARITH_TAC);;
let CONTINUOUS_ON_LIFT_NORM_COMPOSE = 
prove (`!f:real^M->real^N s. f continuous_on s ==> (\x. lift(norm(f x))) continuous_on s`,
let CONTINUOUS_AT_LIFT_NORM = 
prove (`!x. (lift o norm) continuous (at x)`,
let CONTINUOUS_ON_LIFT_NORM = 
prove (`!s. (lift o norm) continuous_on s`,
let CONTINUOUS_AT_LIFT_COMPONENT = 
prove (`!i a. 1 <= i /\ i <= dimindex(:N) ==> (\x:real^N. lift(x$i)) continuous (at a)`,
let CONTINUOUS_ON_LIFT_COMPONENT = 
prove (`!i s. 1 <= i /\ i <= dimindex(:N) ==> (\x:real^N. lift(x$i)) continuous_on s`,
let CONTINUOUS_AT_LIFT_INFNORM = 
prove (`!x:real^N. (lift o infnorm) continuous (at x)`,
let CONTINUOUS_AT_LIFT_DIST = 
prove (`!a:real^N x. (lift o (\x. dist(a,x))) continuous (at x)`,
REWRITE_TAC[CONTINUOUS_AT_LIFT_RANGE] THEN MESON_TAC[NORM_ARITH `abs(dist(a:real^N,x) - dist(a,y)) <= norm(x - y)`; REAL_LET_TRANS]);;
let CONTINUOUS_ON_LIFT_DIST = 
prove (`!a s. (lift o (\x. dist(a,x))) continuous_on s`,
REWRITE_TAC[CONTINUOUS_ON_LIFT_RANGE] THEN MESON_TAC[NORM_ARITH `abs(dist(a:real^N,x) - dist(a,y)) <= norm(x - y)`; REAL_LET_TRANS]);;
(* ------------------------------------------------------------------------- *) (* 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`]);;
let CONTINUOUS_ATTAINS_SUP = 
prove (`!f:real^N->real s. compact s /\ ~(s = {}) /\ (lift o f) continuous_on s ==> ?x. x IN s /\ !y. y IN s ==> f(y) <= f(x)`,
REPEAT STRIP_TAC THEN MP_TAC(SPEC `IMAGE (f:real^N->real) s` COMPACT_ATTAINS_SUP) THEN ASM_SIMP_TAC[GSYM IMAGE_o; COMPACT_CONTINUOUS_IMAGE; IMAGE_EQ_EMPTY] THEN MESON_TAC[IN_IMAGE]);;
let CONTINUOUS_ATTAINS_INF = 
prove (`!f:real^N->real s. compact s /\ ~(s = {}) /\ (lift o f) continuous_on s ==> ?x. x IN s /\ !y. y IN s ==> f(x) <= f(y)`,
REPEAT STRIP_TAC THEN MP_TAC(SPEC `IMAGE (f:real^N->real) s` COMPACT_ATTAINS_INF) THEN ASM_SIMP_TAC[GSYM IMAGE_o; COMPACT_CONTINUOUS_IMAGE; IMAGE_EQ_EMPTY] THEN MESON_TAC[IN_IMAGE]);;
let DISTANCE_ATTAINS_SUP = 
prove (`!s a. compact s /\ ~(s = {}) ==> ?x. x IN s /\ !y. y IN s ==> dist(a,y) <= dist(a,x)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ATTAINS_SUP THEN ASM_REWRITE_TAC[CONTINUOUS_ON_LIFT_RANGE] THEN REWRITE_TAC[dist] THEN ASM_MESON_TAC[REAL_LET_TRANS; REAL_ABS_SUB_NORM; NORM_NEG; VECTOR_ARITH `(a - x) - (a - y) = --(x - y):real^N`]);;
(* ------------------------------------------------------------------------- *) (* For *minimal* distance, we only need closure, not compactness. *) (* ------------------------------------------------------------------------- *)
let DISTANCE_ATTAINS_INF = 
prove (`!s a:real^N. closed s /\ ~(s = {}) ==> ?x. x IN s /\ !y. y IN s ==> dist(a,x) <= dist(a,y)`,
REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN DISCH_THEN(X_CHOOSE_TAC `b:real^N`) THEN MP_TAC(ISPECL [`\x:real^N. dist(a,x)`; `cball(a:real^N,dist(b,a)) INTER s`] CONTINUOUS_ATTAINS_INF) THEN ANTS_TAC THENL [ASM_SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_INTER; BOUNDED_INTER; BOUNDED_CBALL; CLOSED_CBALL; GSYM MEMBER_NOT_EMPTY] THEN REWRITE_TAC[dist; CONTINUOUS_ON_LIFT_RANGE; IN_INTER; IN_CBALL] THEN ASM_MESON_TAC[REAL_LET_TRANS; REAL_ABS_SUB_NORM; NORM_NEG; REAL_LE_REFL; NORM_SUB; VECTOR_ARITH `(a - x) - (a - y) = --(x - y):real^N`]; MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[IN_INTER; IN_CBALL] THEN ASM_MESON_TAC[DIST_SYM; REAL_LE_TOTAL; REAL_LE_TRANS]]);;
(* ------------------------------------------------------------------------- *) (* 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`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_MUL THEN ASM_REWRITE_TAC[LIM_CONST]);;
let CONTINUOUS_VMUL = 
prove (`!net c v. (lift o c) continuous net ==> (\x. c(x) % v) continuous net`,
REWRITE_TAC[continuous; LIM_VMUL; o_THM]);;
let CONTINUOUS_MUL = 
prove (`!net f c. (lift o c) continuous net /\ f continuous net ==> (\x. c(x) % f(x)) continuous net`,
REWRITE_TAC[continuous; LIM_MUL; o_THM]);;
let CONTINUOUS_ON_VMUL = 
prove (`!s c v. (lift o c) continuous_on s ==> (\x. c(x) % v) continuous_on s`,
REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN SIMP_TAC[CONTINUOUS_VMUL]);;
let CONTINUOUS_ON_MUL = 
prove (`!s c f. (lift o c) continuous_on s /\ f continuous_on s ==> (\x. c(x) % f(x)) continuous_on s`,
REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN SIMP_TAC[CONTINUOUS_MUL]);;
let CONTINUOUS_LIFT_POW = 
prove (`!net f:A->real n. (\x. lift(f x)) continuous net ==> (\x. lift(f x pow n)) continuous net`,
REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN INDUCT_TAC THEN ASM_REWRITE_TAC[LIFT_CMUL; real_pow; CONTINUOUS_CONST] THEN MATCH_MP_TAC CONTINUOUS_MUL THEN ASM_REWRITE_TAC[o_DEF]);;
let CONTINUOUS_ON_LIFT_POW = 
prove (`!f:real^N->real s n. (\x. lift(f x)) continuous_on s ==> (\x. lift(f x pow n)) continuous_on s`,
REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN INDUCT_TAC THEN ASM_REWRITE_TAC[LIFT_CMUL; real_pow; CONTINUOUS_ON_CONST] THEN MATCH_MP_TAC CONTINUOUS_ON_MUL THEN ASM_REWRITE_TAC[o_DEF]);;
let CONTINUOUS_LIFT_PRODUCT = 
prove (`!net:(A)net f (t:B->bool). FINITE t /\ (!i. i IN t ==> (\x. lift(f x i)) continuous net) ==> (\x. lift(product t (f x))) continuous net`,
GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[PRODUCT_CLAUSES] THEN REWRITE_TAC[CONTINUOUS_CONST; LIFT_CMUL; FORALL_IN_INSERT] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_MUL THEN ASM_SIMP_TAC[o_DEF]);;
let CONTINUOUS_ON_LIFT_PRODUCT = 
prove (`!f:real^N->A->real s t. FINITE t /\ (!i. i IN t ==> (\x. lift(f x i)) continuous_on s) ==> (\x. lift(product t (f x))) continuous_on s`,
(* ------------------------------------------------------------------------- *) (* 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`,
REPEAT GEN_TAC THEN REWRITE_TAC[LIM] THEN ASM_CASES_TAC `trivial_limit(net:(A)net)` THEN ASM_REWRITE_TAC[] THEN REWRITE_TAC[o_THM; DIST_LIFT] THEN STRIP_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `min (abs(l) / &2) ((l pow 2 * e) / &2)`) THEN REWRITE_TAC[REAL_LT_MIN] THEN ANTS_TAC THENL [ASM_SIMP_TAC[GSYM REAL_ABS_NZ; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN MATCH_MP_TAC REAL_LT_DIV THEN REWRITE_TAC[REAL_OF_NUM_LT; ARITH] THEN ONCE_REWRITE_TAC[GSYM REAL_POW2_ABS] THEN ASM_SIMP_TAC[REAL_LT_MUL; GSYM REAL_ABS_NZ; REAL_POW_LT]; ALL_TAC] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:A` THEN MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `b:A` THEN MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN SIMP_TAC[REAL_LT_RDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN STRIP_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP (REAL_ARITH `abs(x - l) * &2 < abs l ==> ~(x = &0)`)) THEN ASM_SIMP_TAC[REAL_SUB_INV; REAL_ABS_DIV; REAL_LT_LDIV_EQ; GSYM REAL_ABS_NZ; REAL_ENTIRE] THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH `abs(x - y) * &2 < b * c ==> c * b <= d * &2 ==> abs(y - x) < d`)) THEN ASM_SIMP_TAC[GSYM REAL_MUL_ASSOC; REAL_LE_LMUL_EQ] THEN ONCE_REWRITE_TAC[GSYM REAL_POW2_ABS] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN ASM_SIMP_TAC[REAL_ABS_MUL; REAL_POW_2; REAL_MUL_ASSOC; GSYM REAL_ABS_NZ; REAL_LE_RMUL_EQ] THEN ASM_SIMP_TAC[REAL_ARITH `abs(x - y) * &2 < abs y ==> abs y <= &2 * abs x`]);;
let CONTINUOUS_INV = 
prove (`!net f. (lift o f) continuous net /\ ~(f(netlimit net) = &0) ==> (lift o inv o f) continuous net`,
REWRITE_TAC[continuous; LIM_INV; o_THM]);;
let CONTINUOUS_AT_WITHIN_INV = 
prove (`!f s a:real^N. (lift o f) continuous (at a within s) /\ ~(f a = &0) ==> (lift o inv o f) continuous (at a within s)`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `trivial_limit (at (a:real^N) within s)` THENL [ASM_REWRITE_TAC[continuous; LIM]; ASM_SIMP_TAC[NETLIMIT_WITHIN; CONTINUOUS_INV]]);;
let CONTINUOUS_AT_INV = 
prove (`!f a. (lift o f) continuous at a /\ ~(f a = &0) ==> (lift o inv o f) continuous at a`,
ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN REWRITE_TAC[CONTINUOUS_AT_WITHIN_INV]);;
let CONTINUOUS_ON_INV = 
prove (`!f s. (lift o f) continuous_on s /\ (!x. x IN s ==> ~(f x = &0)) ==> (lift o inv o f) continuous_on s`,
(* ------------------------------------------------------------------------- *) (* 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`,
REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[LIM_PASTECART] THEN REPEAT STRIP_TAC THENL [FIRST_ASSUM(MP_TAC o ISPEC `fstcart:real^(M,N)finite_sum->real^M` o MATCH_MP (REWRITE_RULE[IMP_CONJ] LIM_LINEAR)) THEN REWRITE_TAC[LINEAR_FSTCART; FSTCART_PASTECART; ETA_AX]; FIRST_ASSUM(MP_TAC o ISPEC `sndcart:real^(M,N)finite_sum->real^N` o MATCH_MP (REWRITE_RULE[IMP_CONJ] LIM_LINEAR)) THEN REWRITE_TAC[LINEAR_SNDCART; SNDCART_PASTECART; ETA_AX]]);;
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`,
REWRITE_TAC[continuous; LIM_PASTECART]);;
let CONTINUOUS_ON_PASTECART = 
prove (`!f:real^M->real^N g:real^M->real^P s. f continuous_on s /\ g continuous_on s ==> (\x. pastecart (f x) (g x)) continuous_on s`,
let CONNECTED_PCROSS = 
prove (`!s:real^M->bool t:real^N->bool. connected s /\ connected t ==> connected (s PCROSS t)`,
REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS; CONNECTED_IFF_CONNECTED_COMPONENT] THEN DISCH_TAC THEN REWRITE_TAC[FORALL_PASTECART; IN_ELIM_PASTECART_THM] THEN MAP_EVERY X_GEN_TAC [`x1:real^M`; `y1:real^N`; `x2:real^M`; `y2:real^N`] THEN STRIP_TAC THEN FIRST_X_ASSUM(CONJUNCTS_THEN2 (MP_TAC o SPECL [`x1:real^M`; `x2:real^M`]) (MP_TAC o SPECL [`y1:real^N`; `y2:real^N`])) THEN ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; connected_component] THEN X_GEN_TAC `c2:real^N->bool` THEN STRIP_TAC THEN X_GEN_TAC `c1:real^M->bool` THEN STRIP_TAC THEN EXISTS_TAC `IMAGE (\x:real^M. pastecart x y1) c1 UNION IMAGE (\y:real^N. pastecart x2 y) c2` THEN REWRITE_TAC[IN_UNION] THEN REPEAT CONJ_TAC THENL [MATCH_MP_TAC CONNECTED_UNION THEN ASM_SIMP_TAC[CONNECTED_CONTINUOUS_IMAGE; CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER; EXISTS_IN_IMAGE] THEN EXISTS_TAC `x2:real^M` THEN ASM SET_TAC[]; REWRITE_TAC[SUBSET; IN_UNION; FORALL_AND_THM; FORALL_IN_IMAGE; TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN ASM SET_TAC[]; ASM SET_TAC[]; ASM SET_TAC[]]);;
let CONNECTED_PCROSS_EQ = 
prove (`!s:real^M->bool t:real^N->bool. connected (s PCROSS t) <=> s = {} \/ t = {} \/ connected s /\ connected t`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN ASM_CASES_TAC `t:real^N->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN REWRITE_TAC[PCROSS_EMPTY; CONNECTED_EMPTY] THEN EQ_TAC THEN SIMP_TAC[CONNECTED_PCROSS] THEN REWRITE_TAC[PCROSS] THEN REPEAT STRIP_TAC THENL [SUBGOAL_THEN `connected (IMAGE fstcart {pastecart (x:real^M) (y:real^N) | x IN s /\ y IN t})` MP_TAC THENL [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE; ALL_TAC]; SUBGOAL_THEN `connected (IMAGE sndcart {pastecart (x:real^M) (y:real^N) | x IN s /\ y IN t})` MP_TAC THENL [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE; ALL_TAC]] THEN ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_IMAGE; EXISTS_PASTECART; IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN ASM SET_TAC[]);;
let CLOSURE_PCROSS = 
prove (`!s:real^M->bool t:real^N->bool. closure (s PCROSS t) = (closure s) PCROSS (closure t)`,
REWRITE_TAC[EXTENSION; PCROSS; FORALL_PASTECART] THEN REPEAT GEN_TAC THEN REWRITE_TAC[CLOSURE_APPROACHABLE; EXISTS_PASTECART; FORALL_PASTECART] THEN REWRITE_TAC[IN_ELIM_PASTECART_THM; PASTECART_INJ] THEN REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN REWRITE_TAC[dist; PASTECART_SUB] THEN EQ_TAC THENL [MESON_TAC[NORM_LE_PASTECART; REAL_LET_TRANS]; DISCH_TAC] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(CONJUNCTS_THEN (MP_TAC o SPEC `e / &2`)) THEN ASM_MESON_TAC[REAL_HALF; NORM_PASTECART_LE; REAL_ARITH `z <= x + y /\ x < e / &2 /\ y < e / &2 ==> z < e`]);;
let LIMPT_PCROSS = 
prove (`!s:real^M->bool t:real^N->bool x y. x limit_point_of s /\ y limit_point_of t ==> (pastecart x y) limit_point_of (s PCROSS t)`,
REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS; LIMPT_APPROACHABLE; EXISTS_PASTECART] THEN REWRITE_TAC[IN_ELIM_PASTECART_THM; PASTECART_INJ; dist; PASTECART_SUB] THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN FIRST_X_ASSUM(CONJUNCTS_THEN (MP_TAC o SPEC `e / &2`)) THEN ASM_MESON_TAC[REAL_HALF; NORM_PASTECART_LE; REAL_ARITH `z <= x + y /\ x < e / &2 /\ y < e / &2 ==> z < e`]);;
let CLOSED_IN_PCROSS = 
prove (`!s:real^M->bool s' t:real^N->bool t'. closed_in (subtopology euclidean s) s' /\ closed_in (subtopology euclidean t) t' ==> closed_in (subtopology euclidean (s PCROSS t)) (s' PCROSS t')`,
REPEAT GEN_TAC THEN REWRITE_TAC[CLOSED_IN_CLOSED] THEN DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `s'':real^M->bool` STRIP_ASSUME_TAC) (X_CHOOSE_THEN `t'':real^N->bool` STRIP_ASSUME_TAC)) THEN EXISTS_TAC `(s'':real^M->bool) PCROSS (t'':real^N->bool)` THEN ASM_SIMP_TAC[CLOSED_PCROSS; EXTENSION; FORALL_PASTECART] THEN REWRITE_TAC[IN_INTER; PASTECART_IN_PCROSS] THEN ASM SET_TAC[]);;
let CLOSED_IN_PCROSS_EQ = 
prove (`!s s':real^M->bool t t':real^N->bool. closed_in (subtopology euclidean (s PCROSS t)) (s' PCROSS t') <=> s' = {} \/ t' = {} \/ closed_in (subtopology euclidean s) s' /\ closed_in (subtopology euclidean t) t'`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `s':real^M->bool = {}` THEN ASM_REWRITE_TAC[PCROSS_EMPTY; CLOSED_IN_EMPTY] THEN ASM_CASES_TAC `t':real^N->bool = {}` THEN ASM_REWRITE_TAC[PCROSS_EMPTY; CLOSED_IN_EMPTY] THEN EQ_TAC THEN REWRITE_TAC[CLOSED_IN_PCROSS] THEN ASM_REWRITE_TAC[CLOSED_IN_INTER_CLOSURE; CLOSURE_PCROSS; INTER_PCROSS; PCROSS_EQ; PCROSS_EQ_EMPTY]);;
let FRONTIER_PCROSS = 
prove (`!s:real^M->bool t:real^N->bool. frontier(s PCROSS t) = frontier s PCROSS closure t UNION closure s PCROSS frontier t`,
REPEAT GEN_TAC THEN REWRITE_TAC[frontier; CLOSURE_PCROSS; INTERIOR_PCROSS; PCROSS_DIFF] THEN REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_DIFF; IN_UNION; PASTECART_IN_PCROSS] THEN ASM SET_TAC[]);;
(* ------------------------------------------------------------------------- *) (* Hence some useful properties follow quite easily. *) (* ------------------------------------------------------------------------- *)
let CONNECTED_SCALING = 
prove (`!s:real^N->bool c. connected s ==> connected (IMAGE (\x. c % x) s)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN REWRITE_TAC[linear] THEN CONJ_TAC THEN VECTOR_ARITH_TAC);;
let CONNECTED_NEGATIONS = 
prove (`!s:real^N->bool. connected s ==> connected (IMAGE (--) s)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN REWRITE_TAC[linear] THEN CONJ_TAC THEN VECTOR_ARITH_TAC);;
let CONNECTED_SUMS = 
prove (`!s t:real^N->bool. connected s /\ connected t ==> connected {x + y | x IN s /\ y IN t}`,
REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP CONNECTED_PCROSS) THEN DISCH_THEN(MP_TAC o ISPEC `\z. (fstcart z + sndcart z:real^N)` o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] CONNECTED_CONTINUOUS_IMAGE)) THEN SIMP_TAC[CONTINUOUS_ON_ADD; LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART; PCROSS] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM; EXISTS_PASTECART] THEN REWRITE_TAC[PASTECART_INJ; FSTCART_PASTECART; SNDCART_PASTECART] THEN MESON_TAC[]);;
let COMPACT_SCALING = 
prove (`!s:real^N->bool c. compact s ==> compact (IMAGE (\x. c % x) s)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN REWRITE_TAC[linear] THEN CONJ_TAC THEN VECTOR_ARITH_TAC);;
let COMPACT_NEGATIONS = 
prove (`!s:real^N->bool. compact s ==> compact (IMAGE (--) s)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN REWRITE_TAC[linear] THEN CONJ_TAC THEN VECTOR_ARITH_TAC);;
let COMPACT_SUMS = 
prove (`!s:real^N->bool t. compact s /\ compact t ==> compact {x + y | x IN s /\ y IN t}`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `{x + y | x IN s /\ y IN t} = IMAGE (\z. fstcart z + sndcart z :real^N) (s PCROSS t)` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE; PCROSS] THEN GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[FSTCART_PASTECART; SNDCART_PASTECART; PASTECART_FST_SND]; ALL_TAC] THEN MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN ASM_SIMP_TAC[COMPACT_PCROSS] THEN MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN REWRITE_TAC[linear; FSTCART_ADD; FSTCART_CMUL; SNDCART_ADD; SNDCART_CMUL] THEN CONJ_TAC THEN VECTOR_ARITH_TAC);;
let COMPACT_DIFFERENCES = 
prove (`!s:real^N->bool t. compact s /\ compact t ==> compact {x - y | x IN s /\ y IN t}`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `{x - y | x:real^N IN s /\ y IN t} = {x + y | x IN s /\ y IN (IMAGE (--) t)}` (fun th -> ASM_SIMP_TAC[th; COMPACT_SUMS; COMPACT_NEGATIONS]) THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE] THEN ONCE_REWRITE_TAC[VECTOR_ARITH `(x:real^N = --y) <=> (y = --x)`] THEN SIMP_TAC[VECTOR_SUB; GSYM CONJ_ASSOC; UNWIND_THM2] THEN MESON_TAC[VECTOR_NEG_NEG]);;
let COMPACT_AFFINITY = 
prove (`!s a:real^N c. compact s ==> compact (IMAGE (\x. a + c % x) s)`,
REPEAT STRIP_TAC THEN SUBGOAL_THEN `(\x:real^N. a + c % x) = (\x. a + x) o (\x. c % x)` SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN ASM_SIMP_TAC[IMAGE_o; COMPACT_TRANSLATION; COMPACT_SCALING]);;
(* ------------------------------------------------------------------------- *) (* Hence we get the following. *) (* ------------------------------------------------------------------------- *)
let COMPACT_SUP_MAXDISTANCE = 
prove (`!s:real^N->bool. compact s /\ ~(s = {}) ==> ?x y. x IN s /\ y IN s /\ !u v. u IN s /\ v IN s ==> norm(u - v) <= norm(x - y)`,
REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`{x - y:real^N | x IN s /\ y IN s}`; `vec 0:real^N`] DISTANCE_ATTAINS_SUP) THEN ANTS_TAC THENL [ASM_SIMP_TAC[COMPACT_DIFFERENCES] THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY] THEN ASM_MESON_TAC[MEMBER_NOT_EMPTY]; REWRITE_TAC[IN_ELIM_THM; dist; VECTOR_SUB_RZERO; VECTOR_SUB_LZERO; NORM_NEG] THEN MESON_TAC[]]);;
(* ------------------------------------------------------------------------- *) (* We can state this in terms of diameter of a set. *) (* ------------------------------------------------------------------------- *)
let diameter = new_definition
  `diameter s =
        if s = {} then &0
        else sup {norm(x - y) | x IN s /\ y IN s}`;;
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)`,
GEN_TAC THEN DISCH_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_REWRITE_TAC[diameter; NOT_IN_EMPTY; REAL_LET_ANTISYM] THEN MP_TAC(SPEC `{norm(x - y:real^N) | x IN s /\ y IN s}` SUP) THEN ABBREV_TAC `b = sup {norm(x - y:real^N) | x IN s /\ y IN s}` THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN REWRITE_TAC[NOT_IN_EMPTY; real_gt] THEN ANTS_TAC THENL [CONJ_TAC THENL [ASM_MESON_TAC[MEMBER_NOT_EMPTY]; ALL_TAC]; MESON_TAC[REAL_NOT_LE]] THEN SIMP_TAC[VECTOR_SUB; LEFT_IMP_EXISTS_THM] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [bounded]) THEN MESON_TAC[REAL_ARITH `x <= y + z /\ y <= b /\ z<= b ==> x <= b + b`; NORM_TRIANGLE; NORM_NEG]);;
let DIAMETER_BOUNDED_BOUND = 
prove (`!s x y. bounded s /\ x IN s /\ y IN s ==> norm(x - y) <= diameter s`,
MESON_TAC[DIAMETER_BOUNDED]);;
let DIAMETER_COMPACT_ATTAINED = 
prove (`!s:real^N->bool. compact s /\ ~(s = {}) ==> ?x y. x IN s /\ y IN s /\ (norm(x - y) = diameter s)`,
GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_SUP_MAXDISTANCE) THEN REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MP_TAC(SPEC `s:real^N->bool` DIAMETER_BOUNDED) THEN RULE_ASSUM_TAC(REWRITE_RULE[COMPACT_EQ_BOUNDED_CLOSED]) THEN ASM_REWRITE_TAC[real_gt] THEN STRIP_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN ASM_MESON_TAC[NORM_POS_LE; REAL_NOT_LT]);;
let DIAMETER_TRANSLATION = 
prove (`!a s. diameter (IMAGE (\x. a + x) s) = diameter s`,
REWRITE_TAC[diameter] THEN GEOM_TRANSLATE_TAC[]);;
add_translation_invariants [DIAMETER_TRANSLATION];;
let DIAMETER_LINEAR_IMAGE = 
prove (`!f:real^M->real^N s. linear f /\ (!x. norm(f x) = norm x) ==> diameter(IMAGE f s) = diameter s`,
REWRITE_TAC[diameter] THEN REPEAT STRIP_TAC THEN REWRITE_TAC[diameter; IMAGE_EQ_EMPTY] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN REWRITE_TAC[GSYM CONJ_ASSOC; RIGHT_EXISTS_AND_THM; EXISTS_IN_IMAGE] THEN ASM_MESON_TAC[LINEAR_SUB]);;
add_linear_invariants [DIAMETER_LINEAR_IMAGE];;
let DIAMETER_EMPTY = 
prove (`diameter {} = &0`,
REWRITE_TAC[diameter]);;
let DIAMETER_SING = 
prove (`!a. diameter {a} = &0`,
REWRITE_TAC[diameter; NOT_INSERT_EMPTY; IN_SING] THEN REWRITE_TAC[SET_RULE `{f x y | x = a /\ y = a} = {f a a }`] THEN REWRITE_TAC[SUP_SING; VECTOR_SUB_REFL; NORM_0]);;
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_SUBSET_CBALL_NONEMPTY = 
prove (`!s:real^N->bool. bounded s /\ ~(s = {}) ==> ?z. z IN s /\ s SUBSET cball(z,diameter s)`,
REPEAT 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 `a:real^N` THEN DISCH_TAC THEN ASM_REWRITE_TAC[SUBSET] THEN X_GEN_TAC `b:real^N` THEN DISCH_TAC THEN REWRITE_TAC[IN_CBALL; dist] THEN ASM_MESON_TAC[DIAMETER_BOUNDED]);;
let DIAMETER_SUBSET_CBALL = 
prove (`!s:real^N->bool. bounded s ==> ?z. s SUBSET cball(z,diameter s)`,
REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_MESON_TAC[DIAMETER_SUBSET_CBALL_NONEMPTY; EMPTY_SUBSET]);;
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_CBALL = 
prove (`!a:real^N r. diameter(cball(a,r)) = if r < &0 then &0 else &2 * r`,
REPEAT GEN_TAC THEN COND_CASES_TAC THENL [ASM_MESON_TAC[CBALL_EQ_EMPTY; DIAMETER_EMPTY]; ALL_TAC] THEN RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LT]) THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL [MATCH_MP_TAC DIAMETER_LE THEN ASM_SIMP_TAC[CBALL_EQ_EMPTY; REAL_LE_MUL; REAL_POS; REAL_NOT_LT] THEN REWRITE_TAC[IN_CBALL] THEN NORM_ARITH_TAC; MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `norm((a + r % basis 1) - (a - r % basis 1):real^N)` THEN CONJ_TAC THENL [REWRITE_TAC[VECTOR_ARITH `(a + r % b) - (a - r % b:real^N) = (&2 * r) % b`] THEN SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL] THEN ASM_REAL_ARITH_TAC; MATCH_MP_TAC DIAMETER_BOUNDED_BOUND THEN REWRITE_TAC[BOUNDED_CBALL; IN_CBALL] THEN REWRITE_TAC[NORM_ARITH `dist(a:real^N,a + b) = norm b /\ dist(a,a - b) = norm b`] THEN SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL] THEN ASM_REAL_ARITH_TAC]]);;
let DIAMETER_BALL = 
prove (`!a:real^N r. diameter(ball(a,r)) = if r < &0 then &0 else &2 * r`,
REPEAT GEN_TAC THEN COND_CASES_TAC THENL [ASM_SIMP_TAC[BALL_EMPTY; REAL_LT_IMP_LE; DIAMETER_EMPTY]; ALL_TAC] THEN ASM_CASES_TAC `r = &0` THEN ASM_SIMP_TAC[BALL_EMPTY; REAL_LE_REFL; DIAMETER_EMPTY; REAL_MUL_RZERO] THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `diameter(cball(a:real^N,r))` THEN CONJ_TAC THENL [SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN ASM_SIMP_TAC[GSYM CLOSURE_BALL; DIAMETER_CLOSURE; BOUNDED_BALL]; ASM_SIMP_TAC[DIAMETER_CBALL]]);;
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`,
REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_SIMP_TAC[NOT_IN_EMPTY; SET_RULE `{f x y |x,y| F} = {}`; DIAMETER_EMPTY; REAL_ADD_LID; DIAMETER_POS_LE] THEN ASM_CASES_TAC `t:real^N->bool = {}` THEN ASM_SIMP_TAC[NOT_IN_EMPTY; SET_RULE `{f x y |x,y| F} = {}`; DIAMETER_EMPTY; REAL_ADD_RID; DIAMETER_POS_LE] THEN MATCH_MP_TAC DIAMETER_LE THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ; FORALL_IN_GSPEC] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC(NORM_ARITH `norm(x - x') <= s /\ norm(y - y') <= t ==> norm((x + y) - (x' + y'):real^N) <= s + t`) THEN ASM_SIMP_TAC[DIAMETER_BOUNDED_BOUND]);;
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[